diff --git a/app/.env-example.env b/app/.env-example.env index 3ef5bf5c6e..97f0f1e0f6 100644 --- a/app/.env-example.env +++ b/app/.env-example.env @@ -101,3 +101,4 @@ NEXT_PUBLIC_GA_ID=id NEXT_PUBLIC_SCROLL_BADGE_PROVIDER_INFO='[{"badgeContractAddress":"0x71A848A38fFCcA5c7A431F2BB411Ab632Fa0c456","title":"Passport Developer","providers":[{"level":100,"name":"DeveloperList#ContributorPassport10#b1933500","image":"https://raw.githubusercontent.com/passportxyz/passport/10533495e270f7f0706e16d0d7c8ff0e68aa6c34/app/public/assets/zkInfraTalent1.svg"},{"level":200,"name":"DeveloperList#ContributorPassport20#a4d87d4e","image":"https://raw.githubusercontent.com/passportxyz/passport/10533495e270f7f0706e16d0d7c8ff0e68aa6c34/app/public/assets/zkInfraTalent1.svg"},{"level":300,"name":"DeveloperList#ContributorPassport30#4f1f3558","image":"https://raw.githubusercontent.com/passportxyz/passport/10533495e270f7f0706e16d0d7c8ff0e68aa6c34/app/public/assets/zkInfraTalent1.svg"}]},{"badgeContractAddress":"0x71A848A38fFCcA5c7A431F2BB411Ab632Fa0c456","title":"Passport Developer 2","providers":[{"level":100,"name":"DeveloperList#ContributorPassport10#b1933500","image":"https://raw.githubusercontent.com/passportxyz/passport/10533495e270f7f0706e16d0d7c8ff0e68aa6c34/app/public/assets/zkInfraTalent1.svg"},{"level":200,"name":"DeveloperList#ContributorPassport20#a4d87d4e","image":"https://raw.githubusercontent.com/passportxyz/passport/10533495e270f7f0706e16d0d7c8ff0e68aa6c34/app/public/assets/zkInfraTalent1.svg"},{"level":300,"name":"DeveloperList#ContributorPassport30#4f1f3558","image":"https://raw.githubusercontent.com/passportxyz/passport/10533495e270f7f0706e16d0d7c8ff0e68aa6c34/app/public/assets/zkInfraTalent1.svg"}]}]' # testnet NEXT_PUBLIC_SCROLL_CAMPAIGN_CHAIN_ID=0x8274f +NEXT_PUBLIC_SCROLL_CANVAS_PROFILE_REGISTRY_ADDRESS= diff --git a/app/__tests__/components/ScrollCampaign.test.tsx b/app/__tests__/components/ScrollCampaign.test.tsx index 1723f79dd5..a9d6943f95 100644 --- a/app/__tests__/components/ScrollCampaign.test.tsx +++ b/app/__tests__/components/ScrollCampaign.test.tsx @@ -13,8 +13,11 @@ import { useScrollBadge } from "../../hooks/useScrollBadge"; import { ScrollStepsBar } from "../../components/scroll/ScrollLayout"; import { useMintBadge } from "../../hooks/useMintBadge"; import { ProviderWithTitle } from "../../components/ScrollCampaign"; +import { ethers } from "ethers"; +import { scrollCampaignChain } from "../../config/scroll_campaign"; jest.mock("@gitcoin/passport-database-client"); +jest.mock("ethers"); const navigateMock = jest.fn(); jest.mock("react-router-dom", () => ({ @@ -49,8 +52,6 @@ jest.mock("../../utils/helpers", () => { }); jest.mock("../../config/scroll_campaign", () => { - const originalModule = jest.requireActual("../../config/scroll_campaign"); - const mockBadgeProviders = [ { badgeContractAddress: "0xMockContractAddress", @@ -75,13 +76,13 @@ jest.mock("../../config/scroll_campaign", () => { }; return { - ...originalModule, badgeContractInfo: mockBadgeProviders, scrollCampaignBadgeProviderInfo: mockScrollCampaignBadgeProviderInfo, scrollCampaignBadgeProviders: ["SomeDeveloperProvider"], loadBadgeProviders: jest.fn().mockImplementation(() => { return mockBadgeProviders; }), + scrollCampaignChain: { id: "0x1", rpcUrl: "https://example.com" }, }; }); @@ -312,9 +313,6 @@ describe("Github Connect page tests", () => { ); - // const canvasRedirectButton = screen.queryByTestId("canvasRedirectButton"); - // expect(canvasRedirectButton).toBeInTheDocument(); - expect(navigateMock).toHaveBeenCalledTimes(1); }); }); @@ -403,22 +401,36 @@ describe("ScrollCampaign Step 2 (Mint Badge) tests", () => { it("renders ScrollMintingBadge when syncingToChain is true", async () => { (useParams as jest.Mock).mockReturnValue({ campaignId: "scroll-developer", step: "2" }); - const earnedBadges: ProviderWithTitle[] = [ - { - name: "SomeDeveloperProvider" as PROVIDER_ID, - title: "Mock Badge Title", - image: "mockImage.png", - level: 1, + (mockDatabase.getPassport as jest.Mock).mockResolvedValue({ + status: "Success", + passport: { + stamps: [ + { + provider: "SomeDeveloperProvider", + credential: { + credentialSubject: { + hash: "hash:0xMockHash", + }, + }, + }, + ], }, - ]; + }); (useMintBadge as jest.Mock).mockReturnValue({ onMint: jest.fn(), syncingToChain: true, - earnedBadges: earnedBadges, badgesFreshlyMinted: false, }); + const mockContract = { + getProfile: jest.fn().mockResolvedValue("0xMockProfileAddress"), + isProfileMinted: jest.fn().mockResolvedValue(true), + burntProviderHashes: jest.fn().mockResolvedValue(false), + }; + + (ethers.Contract as jest.Mock).mockImplementation(() => mockContract); + renderWithContext( mockCeramicContext, @@ -427,9 +439,11 @@ describe("ScrollCampaign Step 2 (Mint Badge) tests", () => { ); // Verify that the ScrollMintingBadge component is rendered - expect(screen.getByText("Minting badges...")).toBeInTheDocument(); + expect(screen.getByText("Minting badge...")).toBeInTheDocument(); // Check that the badges are displayed - expect(screen.getByText("Mock Badge Title")).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByText("Mock Badge Title")).toBeInTheDocument(); + }); }); }); diff --git a/app/__tests__/components/ScrollMintBadge.test.tsx b/app/__tests__/components/ScrollMintBadge.test.tsx new file mode 100644 index 0000000000..21255af7fd --- /dev/null +++ b/app/__tests__/components/ScrollMintBadge.test.tsx @@ -0,0 +1,398 @@ +import React from "react"; +import { screen, waitFor } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { ethers } from "ethers"; +import { ScrollMintBadge } from "../../components/scroll/ScrollMintPage"; +import { makeTestCeramicContext, renderWithContext } from "../../__test-fixtures__/contextTestHelpers"; +import { PassportDatabase } from "@gitcoin/passport-database-client"; +import axios from "axios"; +import { useMintBadge } from "../../hooks/useMintBadge"; +import { MemoryRouter } from "react-router-dom"; + +jest.mock("axios"); + +jest.mock("ethers"); + +const issueAttestationMock = jest.fn(); + +jest.mock("../../hooks/useAttestation", () => ({ + useAttestation: () => ({ + getNonce: jest.fn().mockImplementation(() => new Promise((resolve) => setTimeout(() => resolve(0), 1000))), + issueAttestation: issueAttestationMock, + needToSwitchChain: false, + }), +})); + +const successMock = jest.fn(); +const failureMock = jest.fn(); +jest.mock("../../hooks/useMessage", () => ({ + useMessage: () => ({ success: successMock, failure: failureMock }), +})); + +jest.mock("../../config/scroll_campaign", () => ({ + scrollCampaignChain: { id: "0x1", rpcUrl: "https://example.com" }, + scrollCampaignBadgeProviders: ["provider1", "provider2", "provider3"], + scrollCampaignBadgeProviderInfo: { + provider1: { contractAddress: "0xContract1", level: 1 }, + provider2: { contractAddress: "0xContract2", level: 2 }, + provider3: { contractAddress: "0xContract3", level: 3 }, + }, + scrollCanvasProfileRegistryAddress: "0xProfileRegistry", +})); + +const mockGetPassport = jest.fn(); + +const mockCeramicContext = makeTestCeramicContext({ + database: Object.assign({}, new PassportDatabase("test", "test", "test"), { + getPassport: mockGetPassport, + }), +}); + +const InnerTestComponent = () => { + const { onMint, syncingToChain } = useMintBadge(); + return ; +}; + +const TestComponent = () => { + return ( + + + + ); +}; + +describe("ScrollMintBadge", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it("renders no badges message when user does not qualify", async () => { + mockGetPassport.mockResolvedValue({ + status: "Success", + passport: { stamps: [] }, + }); + + renderWithContext(mockCeramicContext, ); + + await waitFor(() => { + expect(screen.getByText("We're sorry!")).toBeInTheDocument(); + expect(screen.getByText("You don't qualify for any badges.")).toBeInTheDocument(); + }); + }); + + it("renders congratulations message when user qualifies for badges", async () => { + mockGetPassport.mockResolvedValue({ + status: "Success", + passport: { + stamps: [ + { + provider: "provider1", + credential: { + credentialSubject: { hash: "base64:MTIzNDU2Nzg5MA==" }, + }, + }, + ], + }, + }); + + const mockContract = { + getProfile: jest.fn().mockResolvedValue("0xMockProfileAddress"), + isProfileMinted: jest.fn().mockResolvedValue(true), + burntProviderHashes: jest.fn().mockResolvedValue(false), + }; + + (ethers.Contract as jest.Mock).mockImplementation(() => mockContract); + + renderWithContext(mockCeramicContext, ); + + await waitFor(() => { + expect(screen.getByText("Congratulations!")).toBeInTheDocument(); + expect( + screen.getAllByText( + (_, element) => + element?.textContent === "You qualify for 1 badge. Mint your badge and get a chance to work with us." + ) + ).not.toHaveLength(0); + expect(screen.getByRole("button", { name: /mint badge/i })).toBeInTheDocument(); + }); + }); + + it("handles minting process", async () => { + mockGetPassport.mockResolvedValue({ + status: "Success", + passport: { + stamps: [ + { + provider: "provider1", + credential: { + credentialSubject: { hash: "base64:MTIzNDU2Nzg5MA==" }, + }, + }, + ], + }, + }); + + const mockContract = { + getProfile: jest.fn().mockResolvedValue("0xMockProfileAddress"), + isProfileMinted: jest.fn().mockResolvedValue(true), + burntProviderHashes: jest.fn().mockResolvedValue(false), + }; + + (ethers.Contract as jest.Mock).mockImplementation(() => mockContract); + + (axios.post as jest.Mock).mockResolvedValue({ data: { error: null } }); + + renderWithContext(mockCeramicContext, ); + + await waitFor(() => { + expect(screen.getByRole("button", { name: /mint badge/i })).toBeInTheDocument(); + }); + + const mintButton = screen.getByRole("button", { name: /mint badge/i }); + await userEvent.click(mintButton); + + await waitFor(() => { + expect(screen.getByText("Minting badge...")).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(issueAttestationMock).toHaveBeenCalled(); + }); + }); + + it("handles hash already used by current user", async () => { + const hash = "bla:MTIzNDU2Nzg5MA=="; + const encodedHash = "0x" + Buffer.from(hash.split(":")[1], "base64").toString("hex"); + mockGetPassport.mockResolvedValue({ + status: "Success", + passport: { + stamps: [ + { + provider: "provider1", + credential: { + credentialSubject: { hash }, + }, + }, + ], + }, + }); + + const mockContract = { + getProfile: jest.fn().mockResolvedValue("0xMockProfileAddress"), + isProfileMinted: jest.fn().mockResolvedValue(true), + burntProviderHashes: jest.fn().mockResolvedValue(true), + userProviderHashes: jest.fn().mockResolvedValueOnce(encodedHash).mockRejectedValue(new Error("Invalid")), + }; + + (ethers.Contract as jest.Mock).mockImplementation(() => mockContract); + + renderWithContext(mockCeramicContext, ); + + await waitFor(() => { + expect(screen.getByRole("button", { name: /mint badge/i })).toBeInTheDocument(); + }); + + const mintButton = screen.getByRole("button", { name: /mint badge/i }); + await userEvent.click(mintButton); + + await waitFor(() => { + expect(screen.getByText("Minting badge...")).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(issueAttestationMock).toHaveBeenCalled(); + }); + }); + + it("handles hash already used by another user", async () => { + mockGetPassport.mockResolvedValue({ + status: "Success", + passport: { + stamps: [ + { + provider: "provider1", + credential: { + credentialSubject: { hash: "base64:MTIzNDU2Nzg5MA==" }, + }, + }, + ], + }, + }); + + const mockContract = { + getProfile: jest.fn().mockResolvedValue("0xMockProfileAddress"), + isProfileMinted: jest.fn().mockResolvedValue(true), + burntProviderHashes: jest.fn().mockResolvedValue(true), + userProviderHashes: jest.fn().mockRejectedValue(new Error("Invalid")), + }; + + (ethers.Contract as jest.Mock).mockImplementation(() => mockContract); + + renderWithContext(mockCeramicContext, ); + + await waitFor(() => { + expect( + screen.getByText("Your badge credentials have already been claimed with another address.") + ).toBeInTheDocument(); + expect(screen.queryByRole("button", { name: /mint badge/i })).not.toBeInTheDocument(); + }); + }); + + it("handles errors during passport loading", async () => { + mockGetPassport.mockResolvedValue({ + status: "Error", + }); + + renderWithContext(mockCeramicContext, ); + + await waitFor(() => { + expect(failureMock).toHaveBeenCalledWith({ + title: "Error", + message: "An unexpected error occurred while loading your Passport.", + }); + }); + }); + + it("handles some hash already used by another user", async () => { + const hash = "bla:MTIzNDU2Nzg5MA=="; + const encodedHash = "0x" + Buffer.from(hash.split(":")[1], "base64").toString("hex"); + + mockGetPassport.mockResolvedValue({ + status: "Success", + passport: { + stamps: [ + { + provider: "provider1", + credential: { + credentialSubject: { hash: "base64:MTIzNDU2Nzg5MA==" }, + }, + }, + { + provider: "provider2", + credential: { + credentialSubject: { hash: "base64:MTIzNDU2Nzg5MA=+" }, + }, + }, + { + provider: "provider3", + credential: { + credentialSubject: { hash }, + }, + }, + ], + }, + }); + + const mockContract = { + getProfile: jest.fn().mockResolvedValue("0xMockProfileAddress"), + isProfileMinted: jest.fn().mockResolvedValue(true), + burntProviderHashes: jest + .fn() + .mockResolvedValueOnce(true) + .mockResolvedValueOnce(false) + .mockResolvedValueOnce(true), + userProviderHashes: jest + .fn() + .mockRejectedValueOnce(new Error("Invalid")) + .mockResolvedValueOnce(encodedHash) + .mockRejectedValueOnce(new Error("Invalid")), + }; + + (ethers.Contract as jest.Mock).mockImplementation(() => mockContract); + + renderWithContext(mockCeramicContext, ); + + await waitFor(() => { + expect( + screen.getAllByText( + (_, element) => + element?.textContent === + "You qualify for 2 badges. Mint your badges and get a chance to work with us. (Some badge credentials could not be validated because they have already been claimed on another address.)" + ) + ).not.toHaveLength(0); + expect(screen.queryByRole("button", { name: /mint badge/i })).toBeInTheDocument(); + }); + }); + + it("handles errors during passport loading", async () => { + mockGetPassport.mockResolvedValue({ + status: "Error", + }); + + renderWithContext(mockCeramicContext, ); + + await waitFor(() => { + expect(failureMock).toHaveBeenCalledWith({ + title: "Error", + message: "An unexpected error occurred while loading your Passport.", + }); + }); + }); + + it("renders 'Check Again' button when hasCanvas is false", async () => { + mockGetPassport.mockResolvedValue({ + status: "Success", + passport: { + stamps: [ + { + provider: "provider1", + credential: { + credentialSubject: { hash: "base64:MTIzNDU2Nzg5MA==" }, + }, + }, + ], + }, + }); + + const mockContract = { + burntProviderHashes: jest.fn().mockResolvedValue(false), + getProfile: jest.fn().mockResolvedValue("0xMockProfileAddress"), + isProfileMinted: jest.fn().mockResolvedValue(false), + }; + + (ethers.Contract as jest.Mock).mockImplementation(() => mockContract); + (ethers.JsonRpcProvider as jest.Mock).mockImplementation(() => ({})); + + renderWithContext(mockCeramicContext, ); + + await waitFor(() => { + expect(screen.getByText("Congratulations!")).toBeInTheDocument(); + expect(screen.getByRole("button", { name: /check again/i })).toBeInTheDocument(); + }); + expect(screen.getByText(/It looks like you don't have a Canvas yet/)).toBeInTheDocument(); + expect(screen.getByText("here")).toHaveAttribute("href", "https://scroll.io/canvas"); + }); + + it("handles errors during Canvas check", async () => { + mockGetPassport.mockResolvedValue({ + status: "Success", + passport: { + stamps: [ + { + provider: "provider1", + credential: { + credentialSubject: { hash: "base64:MTIzNDU2Nzg5MA==" }, + }, + }, + ], + }, + }); + + const mockContract = { + burntProviderHashes: jest.fn().mockResolvedValue(false), + getProfile: jest.fn().mockRejectedValue(new Error("Canvas check failed")), + }; + + (ethers.Contract as jest.Mock).mockImplementation(() => mockContract); + (ethers.JsonRpcProvider as jest.Mock).mockImplementation(() => ({})); + + renderWithContext(mockCeramicContext, ); + + await waitFor(() => { + expect(failureMock).toHaveBeenCalledWith({ + title: "Error", + message: "An unexpected error occurred while checking for your Scroll Canvas profile.", + }); + }); + }); +}); diff --git a/app/__tests__/hooks/useMintBadge.test.tsx b/app/__tests__/hooks/useMintBadge.test.tsx index 5e6fdf139e..5e4cdf2b13 100644 --- a/app/__tests__/hooks/useMintBadge.test.tsx +++ b/app/__tests__/hooks/useMintBadge.test.tsx @@ -2,16 +2,12 @@ import { renderHook, act } from "@testing-library/react-hooks"; import { useMintBadge } from "../../hooks/useMintBadge"; import { useAttestation } from "../../hooks/useAttestation"; -import { useScrollStampsStore } from "../../context/scrollCampaignStore"; import { jsonRequest } from "../../utils/AttestationProvider"; import { useMessage } from "../../hooks/useMessage"; import { useNavigateToLastStep } from "../../hooks/useNextCampaignStep"; import { useWeb3ModalAccount } from "@web3modal/ethers/react"; -import { ProviderWithTitle } from "../../components/ScrollCampaign"; -import { PROVIDER_ID } from "@gitcoin/passport-types"; jest.mock("../../hooks/useAttestation"); -jest.mock("../../context/scrollCampaignStore"); jest.mock("../../utils/AttestationProvider"); jest.mock("../../hooks/useMessage"); jest.mock("../../hooks/useNextCampaignStep"); @@ -32,10 +28,6 @@ describe("useMintBadge hook", () => { issueAttestation: mockIssueAttestation, }); - (useScrollStampsStore as jest.Mock).mockReturnValue({ - credentials: [{ credential: "testCredential" }], - }); - (useWeb3ModalAccount as jest.Mock).mockReturnValue({ address: "0xTestAddress", }); @@ -51,8 +43,10 @@ describe("useMintBadge hook", () => { it("handles successful minting", async () => { // Arrange - const testBadges: ProviderWithTitle[] = [ - { name: "Provider1" as PROVIDER_ID, title: "Badge Title", image: "", level: 1 }, + const testCredentials = [ + { + credential: "testCredential", + }, ]; const testNonce = 123; const testData = { attestation: "testAttestation" }; @@ -65,7 +59,7 @@ describe("useMintBadge hook", () => { // Act await act(async () => { - await result.current.onMint(testBadges); + await result.current.onMint({ credentials: testCredentials }); }); // Assert @@ -82,14 +76,15 @@ describe("useMintBadge hook", () => { // Check state updates expect(result.current.syncingToChain).toBe(false); - expect(result.current.earnedBadges).toEqual(testBadges); expect(result.current.badgesFreshlyMinted).toBe(true); }); it("shows failure message when nonce is undefined", async () => { // Arrange - const testBadges: ProviderWithTitle[] = [ - { name: "Provider1" as PROVIDER_ID, title: "Badge Title", image: "", level: 1 }, + const testCredentials = [ + { + credential: "testCredential", + }, ]; mockGetNonce.mockResolvedValue(undefined); @@ -98,7 +93,7 @@ describe("useMintBadge hook", () => { // Act await act(async () => { - await result.current.onMint(testBadges); + await result.current.onMint({ credentials: testCredentials }); }); // Assert @@ -118,8 +113,10 @@ describe("useMintBadge hook", () => { it("shows failure message when attestation generation returns an error", async () => { // Arrange - const testBadges: ProviderWithTitle[] = [ - { name: "Provider1" as PROVIDER_ID, title: "Badge Title", image: "", level: 1 }, + const testCredentials = [ + { + credential: "testCredential", + }, ]; const testNonce = 123; @@ -130,7 +127,7 @@ describe("useMintBadge hook", () => { // Act await act(async () => { - await result.current.onMint(testBadges); + await result.current.onMint({ credentials: testCredentials }); }); // Assert @@ -150,8 +147,10 @@ describe("useMintBadge hook", () => { it("shows failure message when issueAttestation throws an error", async () => { // Arrange - const testBadges: ProviderWithTitle[] = [ - { name: "Provider1" as PROVIDER_ID, title: "Badge Title", image: "", level: 1 }, + const testCredentials = [ + { + credential: "testCredential", + }, ]; const testNonce = 123; const testData = { attestation: "testAttestation" }; @@ -164,7 +163,7 @@ describe("useMintBadge hook", () => { // Act await act(async () => { - await result.current.onMint(testBadges); + await result.current.onMint({ credentials: testCredentials }); }); // Assert @@ -184,8 +183,10 @@ describe("useMintBadge hook", () => { it("handles general exception during onMint", async () => { // Arrange - const testBadges: ProviderWithTitle[] = [ - { name: "Provider1" as PROVIDER_ID, title: "Badge Title", image: "", level: 1 }, + const testCredentials = [ + { + credential: "testCredential", + }, ]; const testNonce = 123; @@ -196,7 +197,7 @@ describe("useMintBadge hook", () => { // Act await act(async () => { - await result.current.onMint(testBadges); + await result.current.onMint({ credentials: testCredentials }); }); // Assert diff --git a/app/abi/PassportScoreScrollBadge.json b/app/abi/PassportScoreScrollBadge.json index 8ef5cdfb68..99a4fcdbec 100644 --- a/app/abi/PassportScoreScrollBadge.json +++ b/app/abi/PassportScoreScrollBadge.json @@ -1,20 +1,23 @@ { "abi": [ { - "type": "constructor", + "type": "function", + "name": "hasBadge", "inputs": [ { - "name": "resolver_", + "name": "user", "type": "address", "internalType": "address" - }, + } + ], + "outputs": [ { - "name": "gitcoinPassportDecoder_", - "type": "address", - "internalType": "address" + "name": "", + "type": "bool", + "internalType": "bool" } ], - "stateMutability": "nonpayable" + "stateMutability": "view" }, { "type": "function", @@ -37,29 +40,34 @@ }, { "type": "function", - "name": "badgeLevelDescriptions", + "name": "burntProviderHashes", "inputs": [ { - "name": "", - "type": "uint256", - "internalType": "uint256" + "name": "hash", + "type": "bytes32", + "internalType": "bytes32" } ], "outputs": [ { "name": "", - "type": "string", - "internalType": "string" + "type": "bool", + "internalType": "bool" } ], "stateMutability": "view" }, { "type": "function", - "name": "badgeLevelImageURIs", + "name": "userProviderHashes", "inputs": [ { - "name": "", + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "index", "type": "uint256", "internalType": "uint256" } @@ -67,15 +75,15 @@ "outputs": [ { "name": "", - "type": "string", - "internalType": "string" + "type": "bytes32", + "internalType": "bytes32" } ], "stateMutability": "view" }, { "type": "function", - "name": "badgeLevelNames", + "name": "badgeLevelDescriptions", "inputs": [ { "name": "", @@ -94,12 +102,12 @@ }, { "type": "function", - "name": "badgeTokenURI", + "name": "badgeLevelImageURIs", "inputs": [ { - "name": "uid", - "type": "bytes32", - "internalType": "bytes32" + "name": "", + "type": "uint256", + "internalType": "uint256" } ], "outputs": [ @@ -113,26 +121,26 @@ }, { "type": "function", - "name": "canUpgrade", + "name": "badgeLevelNames", "inputs": [ { - "name": "uid", - "type": "bytes32", - "internalType": "bytes32" + "name": "", + "type": "uint256", + "internalType": "uint256" } ], "outputs": [ { "name": "", - "type": "bool", - "internalType": "bool" + "type": "string", + "internalType": "string" } ], "stateMutability": "view" }, { "type": "function", - "name": "getAndValidateBadge", + "name": "badgeTokenURI", "inputs": [ { "name": "uid", @@ -143,104 +151,20 @@ "outputs": [ { "name": "", - "type": "tuple", - "internalType": "struct Attestation", - "components": [ - { - "name": "uid", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "schema", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "time", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "expirationTime", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "revocationTime", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "refUID", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "recipient", - "type": "address", - "internalType": "address" - }, - { - "name": "attester", - "type": "address", - "internalType": "address" - }, - { - "name": "revocable", - "type": "bool", - "internalType": "bool" - }, - { - "name": "data", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "gitcoinPassportDecoder", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "contract IGitcoinPassportDecoder" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "hasBadge", - "inputs": [ - { - "name": "user", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" + "type": "string", + "internalType": "string" } ], "stateMutability": "view" }, { "type": "function", - "name": "isAttester", + "name": "canUpgrade", "inputs": [ { - "name": "", - "type": "address", - "internalType": "address" + "name": "uid", + "type": "bytes32", + "internalType": "bytes32" } ], "outputs": [ @@ -252,77 +176,6 @@ ], "stateMutability": "view" }, - { - "type": "function", - "name": "issueBadge", - "inputs": [ - { - "name": "attestation", - "type": "tuple", - "internalType": "struct Attestation", - "components": [ - { - "name": "uid", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "schema", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "time", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "expirationTime", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "revocationTime", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "refUID", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "recipient", - "type": "address", - "internalType": "address" - }, - { - "name": "attester", - "type": "address", - "internalType": "address" - }, - { - "name": "revocable", - "type": "bool", - "internalType": "bool" - }, - { - "name": "data", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "nonpayable" - }, { "type": "function", "name": "levelThresholds", @@ -341,1456 +194,6 @@ } ], "stateMutability": "view" - }, - { - "type": "function", - "name": "owner", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "renounceOwnership", - "inputs": [], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "resolver", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "revokeBadge", - "inputs": [ - { - "name": "attestation", - "type": "tuple", - "internalType": "struct Attestation", - "components": [ - { - "name": "uid", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "schema", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "time", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "expirationTime", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "revocationTime", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "refUID", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "recipient", - "type": "address", - "internalType": "address" - }, - { - "name": "attester", - "type": "address", - "internalType": "address" - }, - { - "name": "revocable", - "type": "bool", - "internalType": "bool" - }, - { - "name": "data", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "setBadgeLevelDescriptions", - "inputs": [ - { - "name": "badgeLevelDescriptions_", - "type": "string[]", - "internalType": "string[]" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "setBadgeLevelImageURIs", - "inputs": [ - { - "name": "badgeLevelImageURIs_", - "type": "string[]", - "internalType": "string[]" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "setBadgeLevelNames", - "inputs": [ - { - "name": "badgeLevelNames_", - "type": "string[]", - "internalType": "string[]" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "setLevelThresholds", - "inputs": [ - { - "name": "levelsThresholds_", - "type": "uint256[]", - "internalType": "uint256[]" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "toggleAttester", - "inputs": [ - { - "name": "attester", - "type": "address", - "internalType": "address" - }, - { - "name": "enable", - "type": "bool", - "internalType": "bool" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "transferOwnership", - "inputs": [ - { - "name": "newOwner", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "upgrade", - "inputs": [ - { - "name": "uid", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "event", - "name": "IssueBadge", - "inputs": [ - { - "name": "uid", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "OwnershipTransferred", - "inputs": [ - { - "name": "previousOwner", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "newOwner", - "type": "address", - "indexed": true, - "internalType": "address" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "RevokeBadge", - "inputs": [ - { - "name": "uid", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "Upgrade", - "inputs": [ - { - "name": "oldLevel", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - }, - { - "name": "newLevel", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "error", - "name": "AttestationBadgeMismatch", - "inputs": [ - { - "name": "uid", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "CannotUpgrade", - "inputs": [ - { - "name": "uid", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "SingletonBadge", - "inputs": [] - }, - { - "type": "error", - "name": "Unauthorized", - "inputs": [] - } - ], - "bytecode": { - "object": "0x60a06040523480156200001157600080fd5b5060405162001be038038062001be08339810160408190526200003491620000da565b8162000040336200006d565b6001600160a01b03908116608052600380546001600160a01b031916929091169190911790555062000112565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114620000d557600080fd5b919050565b60008060408385031215620000ee57600080fd5b620000f983620000bd565b91506200010960208401620000bd565b90509250929050565b608051611a9d62000143600039600081816101620152818161079b015281816109a70152610b620152611a9d6000f3fe608060405234801561001057600080fd5b50600436106101585760003560e01c80638298b030116100c3578063bc444e131161007c578063bc444e1314610346578063d753a63d14610359578063d84a4a5e1461036c578063f2fde38b1461037f578063f942ebd614610392578063ffa679b7146103a557600080fd5b80638298b030146102b95780638b2c41bc146102cc5780638c6f12f0146102df5780638da5cb5b146102ff578063b6ebe53914610310578063bb2ae6bf1461033357600080fd5b80632c01c7a4116101155780632c01c7a41461020f57806342faaa7e1461022257806343e839cf146102505780635c445412146102635780635e50864f14610276578063715018a6146102b157600080fd5b806304f3bcec1461015d5780630d713004146101a15780630ee48948146101c1578063114c05df146101d65780632149ee55146101e957806324830563146101fc575b600080fd5b6101847f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6101b46101af36600461113e565b6103b8565b60405161019891906111a7565b6101d46101cf3660046111dd565b610464565b005b6101d46101e43660046112cf565b610497565b600354610184906001600160a01b031681565b6101b461020a36600461113e565b6104b6565b6101d461021d3660046112cf565b610723565b61024261023036600461113e565b60086020526000908152604090205481565b604051908152602001610198565b6101d461025e3660046112cf565b61073e565b61024261027136600461113e565b610759565b6102a16102843660046113c3565b6001600160a01b0316600090815260016020526040902054151590565b6040519015158152602001610198565b6101d461077a565b6102a16102c73660046113e0565b61078e565b6102426102da3660046113c3565b61086a565b6102f26102ed36600461113e565b610938565b604051610198919061141b565b6000546001600160a01b0316610184565b6102a161031e3660046113c3565b60026020526000908152604090205460ff1681565b6101d46103413660046114ef565b610a63565b6101d461035436600461113e565b610a7e565b6102a16103673660046113e0565b610b55565b6101b461037a36600461113e565b610c31565b6101d461038d3660046113c3565b610c41565b6102a16103a036600461113e565b610cba565b6101b46103b336600461113e565b610cf1565b600681815481106103c857600080fd5b9060005260206000200160009150905080546103e39061157f565b80601f016020809104026020016040519081016040528092919081815260200182805461040f9061157f565b801561045c5780601f106104315761010080835404028352916020019161045c565b820191906000526020600020905b81548152906001019060200180831161043f57829003601f168201915b505050505081565b61046c610d01565b6001600160a01b03919091166000908152600260205260409020805460ff1916911515919091179055565b61049f610d01565b80516104b2906005906020840190611035565b5050565b600081815260086020526040812054600680546060939190839081106104de576104de6115b9565b9060005260206000200180546104f39061157f565b80601f016020809104026020016040519081016040528092919081815260200182805461051f9061157f565b801561056c5780601f106105415761010080835404028352916020019161056c565b820191906000526020600020905b81548152906001019060200180831161054f57829003601f168201915b50505050509050600060078381548110610588576105886115b9565b90600052602060002001805461059d9061157f565b80601f01602080910402602001604051908101604052809291908181526020018280546105c99061157f565b80156106165780601f106105eb57610100808354040283529160200191610616565b820191906000526020600020905b8154815290600101906020018083116105f957829003601f168201915b50505050509050600060058481548110610632576106326115b9565b9060005260206000200180546106479061157f565b80601f01602080910402602001604051908101604052809291908181526020018280546106739061157f565b80156106c05780601f10610695576101008083540402835291602001916106c0565b820191906000526020600020905b8154815290600101906020018083116106a357829003601f168201915b5050505050905060006106f58484846040516020016106e1939291906115cf565b604051602081830303815290604052610d5b565b9050806040516020016107089190611670565b60405160208183030381529060405295505050505050919050565b61072b610d01565b80516104b2906007906020840190611035565b610746610d01565b80516104b2906006906020840190611035565b6004818154811061076957600080fd5b600091825260209091200154905081565b610782610d01565b61078c6000610ead565b565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146107d8576040516282b42960e81b815260040160405180910390fd5b6107e182610efd565b6107ed57506000919050565b600180600061080260e0860160c087016113c3565b6001600160a01b03166001600160a01b03168152602001908152602001600020600082825461083191906116cb565b90915550506040518235907f504e4727721de18c6bf7f66448a6ff6da00aa4b1f00b6034e71723ae7ce6373a90600090a2506001919050565b600354604051630d47875d60e41b81526001600160a01b038381166004830152600092839291169063d47875d090602401602060405180830381865afa1580156108b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108dc91906116de565b90506000805b60045481101561093057600481815481106108ff576108ff6115b9565b9060005260206000200154831061091e5761091b8160016116f7565b91505b806109288161170a565b9150506108e2565b509392505050565b604080516101408101825260008082526020820181905281830181905260608083018290526080830182905260a0830182905260c0830182905260e08301829052610100830182905261012083015291516308c6f12f60e41b8152600481018490529091906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690638c6f12f090602401600060405180830381865afa1580156109ee573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a16919081019061179a565b90506000610a28826101200151610f0e565b5090506001600160a01b0381163014610a5c5760405163b923d26160e01b8152600481018590526024015b60405180910390fd5b5092915050565b610a6b610d01565b80516104b290600490602084019061108b565b6000610a8982610938565b90508060c001516001600160a01b0316336001600160a01b031614610ac0576040516282b42960e81b815260040160405180910390fd5b6000610acf8260c0015161086a565b600084815260086020526040902054909150808211610b0457604051634327880b60e11b815260048101859052602401610a53565b60008481526008602090815260409182902084905581518381529081018490527feb0ebb51128928d7b1a6419c52128a9319bfcb55f0adafea75afbf75f9f2f3e9910160405180910390a150505050565b6000336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610b9f576040516282b42960e81b815260040160405180910390fd5b610ba882610f2f565b610bb457506000919050565b6001806000610bc960e0860160c087016113c3565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254610bf891906116f7565b90915550506040518235907fa0785ec0b9bf31a5475d33c716fb9f500f0ea0bb9e4bc10ec39d5db763c1da1590600090a2506001919050565b600781815481106103c857600080fd5b610c49610d01565b6001600160a01b038116610cae5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a53565b610cb781610ead565b50565b600080610cc683610938565b90506000610cd78260c0015161086a565b600094855260086020526040909420549093119392505050565b600581815481106103c857600080fd5b6000546001600160a01b0316331461078c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a53565b60608151600003610d7a57505060408051602081019091526000815290565b6000604051806060016040528060408152602001611a286040913990506000600384516002610da991906116f7565b610db39190611890565b610dbe9060046118b2565b6001600160401b03811115610dd557610dd5611216565b6040519080825280601f01601f191660200182016040528015610dff576020820181803683370190505b509050600182016020820185865187015b80821015610e6b576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f8116850151845350600183019250610e10565b5050600386510660018114610e875760028114610e9a57610ea2565b603d6001830353603d6002830353610ea2565b603d60018303535b509195945050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000610f0882610f8a565b92915050565b6000606082806020019051810190610f2691906118c9565b91509150915091565b600080610f456102da60e0850160c086016113c3565b905080600003610f67576040516282b42960e81b815260040160405180910390fd5b82356000908152600860205260409020819055610f8383610f95565b9392505050565b6000610f0882610fe5565b6000610fa082610fe5565b610fac57506000919050565b610fbf61028460e0840160c085016113c3565b15610fdd57604051630c59311960e11b815260040160405180910390fd5b506001919050565b600060026000610ffc610100850160e086016113c3565b6001600160a01b0316815260208101919091526040016000205460ff16610fdd576040516282b42960e81b815260040160405180910390fd5b82805482825590600052602060002090810192821561107b579160200282015b8281111561107b578251829061106b9082611968565b5091602001919060010190611055565b506110879291506110d2565b5090565b8280548282559060005260206000209081019282156110c6579160200282015b828111156110c65782518255916020019190600101906110ab565b506110879291506110ef565b808211156110875760006110e68282611104565b506001016110d2565b5b8082111561108757600081556001016110f0565b5080546111109061157f565b6000825580601f10611120575050565b601f016020900490600052602060002090810190610cb791906110ef565b60006020828403121561115057600080fd5b5035919050565b60005b8381101561117257818101518382015260200161115a565b50506000910152565b60008151808452611193816020860160208601611157565b601f01601f19169290920160200192915050565b602081526000610f83602083018461117b565b6001600160a01b0381168114610cb757600080fd5b8015158114610cb757600080fd5b600080604083850312156111f057600080fd5b82356111fb816111ba565b9150602083013561120b816111cf565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60405161014081016001600160401b038111828210171561124f5761124f611216565b60405290565b604051601f8201601f191681016001600160401b038111828210171561127d5761127d611216565b604052919050565b60006001600160401b0382111561129e5761129e611216565b5060051b60200190565b60006001600160401b038211156112c1576112c1611216565b50601f01601f191660200190565b600060208083850312156112e257600080fd5b82356001600160401b03808211156112f957600080fd5b818501915085601f83011261130d57600080fd5b813561132061131b82611285565b611255565b81815260059190911b8301840190848101908883111561133f57600080fd5b8585015b838110156113b65780358581111561135b5760008081fd5b8601603f81018b1361136d5760008081fd5b87810135604061137f61131b836112a8565b8281528d828486010111156113945760008081fd5b828285018c83013760009281018b019290925250845250918601918601611343565b5098975050505050505050565b6000602082840312156113d557600080fd5b8135610f83816111ba565b6000602082840312156113f257600080fd5b81356001600160401b0381111561140857600080fd5b82016101408185031215610f8357600080fd5b6020815281516020820152602082015160408201526000604083015161144c60608401826001600160401b03169052565b5060608301516001600160401b03811660808401525060808301516001600160401b03811660a08401525060a083015160c083015260c083015161149b60e08401826001600160a01b03169052565b5060e08301516101006114b8818501836001600160a01b03169052565b84015190506101206114cd8482018315159052565b8401516101408481015290506114e761016084018261117b565b949350505050565b6000602080838503121561150257600080fd5b82356001600160401b0381111561151857600080fd5b8301601f8101851361152957600080fd5b803561153761131b82611285565b81815260059190911b8201830190838101908783111561155657600080fd5b928401925b828410156115745783358252928401929084019061155b565b979650505050505050565b600181811c9082168061159357607f821691505b6020821081036115b357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b683d913730b6b2911d1160b91b815283516000906115f4816009850160208901611157565b71111610113232b9b1b934b83a34b7b7111d1160711b600991840191820152845161162681601b840160208901611157565b6c1116101134b6b0b3b2911d101160991b601b92909101918201528351611654816028840160208801611157565b61227d60f01b60289290910191820152602a0195945050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152600082516116a881601d850160208701611157565b91909101601d0192915050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610f0857610f086116b5565b6000602082840312156116f057600080fd5b5051919050565b80820180821115610f0857610f086116b5565b60006001820161171c5761171c6116b5565b5060010190565b80516001600160401b038116811461173a57600080fd5b919050565b805161173a816111ba565b805161173a816111cf565b600082601f83011261176657600080fd5b815161177461131b826112a8565b81815284602083860101111561178957600080fd5b6114e7826020830160208701611157565b6000602082840312156117ac57600080fd5b81516001600160401b03808211156117c357600080fd5b9083019061014082860312156117d857600080fd5b6117e061122c565b82518152602083015160208201526117fa60408401611723565b604082015261180b60608401611723565b606082015261181c60808401611723565b608082015260a083015160a082015261183760c0840161173f565b60c082015261184860e0840161173f565b60e082015261010061185b81850161174a565b90820152610120838101518381111561187357600080fd5b61187f88828701611755565b918301919091525095945050505050565b6000826118ad57634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417610f0857610f086116b5565b600080604083850312156118dc57600080fd5b82516118e7816111ba565b60208401519092506001600160401b0381111561190357600080fd5b61190f85828601611755565b9150509250929050565b601f82111561196357600081815260208120601f850160051c810160208610156119405750805b601f850160051c820191505b8181101561195f5782815560010161194c565b5050505b505050565b81516001600160401b0381111561198157611981611216565b6119958161198f845461157f565b84611919565b602080601f8311600181146119ca57600084156119b25750858301515b600019600386901b1c1916600185901b17855561195f565b600085815260208120601f198616915b828110156119f9578886015182559484019460019091019084016119da565b5085821015611a175787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa2646970667358221220c6cd53582319cbc27735f3f52b01120dfa184ec184b0b43dd30fcc9d5d290f5664736f6c63430008130033", - "sourceMap": "890:6033:59:-:0;;;2211:229;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2295:9;936:32:32;719:10:37;936:18:32;:32::i;:::-;-1:-1:-1;;;;;966:20:2;;;;;2338:22:59::2;:95:::0;;-1:-1:-1;;;;;;2338:95:59::2;::::0;;;::::2;::::0;;;::::2;::::0;;-1:-1:-1;890:6033:59;;2426:187:32;2499:16;2518:6;;-1:-1:-1;;;;;2534:17:32;;;-1:-1:-1;;;;;;2534:17:32;;;;;;2566:40;;2518:6;;;;;;;2566:40;;2499:16;2566:40;2489:124;2426:187;:::o;14:177:61:-;93:13;;-1:-1:-1;;;;;135:31:61;;125:42;;115:70;;181:1;178;171:12;115:70;14:177;;;:::o;196:293::-;275:6;283;336:2;324:9;315:7;311:23;307:32;304:52;;;352:1;349;342:12;304:52;375:40;405:9;375:40;:::i;:::-;365:50;;434:49;479:2;468:9;464:18;434:49;:::i;:::-;424:59;;196:293;;;;;:::o;:::-;890:6033:59;;;;;;;;;;;;;;;;;;;;;;;;;;;", - "linkReferences": {} - }, - "deployedBytecode": { - "object": "0x608060405234801561001057600080fd5b50600436106101585760003560e01c80638298b030116100c3578063bc444e131161007c578063bc444e1314610346578063d753a63d14610359578063d84a4a5e1461036c578063f2fde38b1461037f578063f942ebd614610392578063ffa679b7146103a557600080fd5b80638298b030146102b95780638b2c41bc146102cc5780638c6f12f0146102df5780638da5cb5b146102ff578063b6ebe53914610310578063bb2ae6bf1461033357600080fd5b80632c01c7a4116101155780632c01c7a41461020f57806342faaa7e1461022257806343e839cf146102505780635c445412146102635780635e50864f14610276578063715018a6146102b157600080fd5b806304f3bcec1461015d5780630d713004146101a15780630ee48948146101c1578063114c05df146101d65780632149ee55146101e957806324830563146101fc575b600080fd5b6101847f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6101b46101af36600461113e565b6103b8565b60405161019891906111a7565b6101d46101cf3660046111dd565b610464565b005b6101d46101e43660046112cf565b610497565b600354610184906001600160a01b031681565b6101b461020a36600461113e565b6104b6565b6101d461021d3660046112cf565b610723565b61024261023036600461113e565b60086020526000908152604090205481565b604051908152602001610198565b6101d461025e3660046112cf565b61073e565b61024261027136600461113e565b610759565b6102a16102843660046113c3565b6001600160a01b0316600090815260016020526040902054151590565b6040519015158152602001610198565b6101d461077a565b6102a16102c73660046113e0565b61078e565b6102426102da3660046113c3565b61086a565b6102f26102ed36600461113e565b610938565b604051610198919061141b565b6000546001600160a01b0316610184565b6102a161031e3660046113c3565b60026020526000908152604090205460ff1681565b6101d46103413660046114ef565b610a63565b6101d461035436600461113e565b610a7e565b6102a16103673660046113e0565b610b55565b6101b461037a36600461113e565b610c31565b6101d461038d3660046113c3565b610c41565b6102a16103a036600461113e565b610cba565b6101b46103b336600461113e565b610cf1565b600681815481106103c857600080fd5b9060005260206000200160009150905080546103e39061157f565b80601f016020809104026020016040519081016040528092919081815260200182805461040f9061157f565b801561045c5780601f106104315761010080835404028352916020019161045c565b820191906000526020600020905b81548152906001019060200180831161043f57829003601f168201915b505050505081565b61046c610d01565b6001600160a01b03919091166000908152600260205260409020805460ff1916911515919091179055565b61049f610d01565b80516104b2906005906020840190611035565b5050565b600081815260086020526040812054600680546060939190839081106104de576104de6115b9565b9060005260206000200180546104f39061157f565b80601f016020809104026020016040519081016040528092919081815260200182805461051f9061157f565b801561056c5780601f106105415761010080835404028352916020019161056c565b820191906000526020600020905b81548152906001019060200180831161054f57829003601f168201915b50505050509050600060078381548110610588576105886115b9565b90600052602060002001805461059d9061157f565b80601f01602080910402602001604051908101604052809291908181526020018280546105c99061157f565b80156106165780601f106105eb57610100808354040283529160200191610616565b820191906000526020600020905b8154815290600101906020018083116105f957829003601f168201915b50505050509050600060058481548110610632576106326115b9565b9060005260206000200180546106479061157f565b80601f01602080910402602001604051908101604052809291908181526020018280546106739061157f565b80156106c05780601f10610695576101008083540402835291602001916106c0565b820191906000526020600020905b8154815290600101906020018083116106a357829003601f168201915b5050505050905060006106f58484846040516020016106e1939291906115cf565b604051602081830303815290604052610d5b565b9050806040516020016107089190611670565b60405160208183030381529060405295505050505050919050565b61072b610d01565b80516104b2906007906020840190611035565b610746610d01565b80516104b2906006906020840190611035565b6004818154811061076957600080fd5b600091825260209091200154905081565b610782610d01565b61078c6000610ead565b565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146107d8576040516282b42960e81b815260040160405180910390fd5b6107e182610efd565b6107ed57506000919050565b600180600061080260e0860160c087016113c3565b6001600160a01b03166001600160a01b03168152602001908152602001600020600082825461083191906116cb565b90915550506040518235907f504e4727721de18c6bf7f66448a6ff6da00aa4b1f00b6034e71723ae7ce6373a90600090a2506001919050565b600354604051630d47875d60e41b81526001600160a01b038381166004830152600092839291169063d47875d090602401602060405180830381865afa1580156108b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108dc91906116de565b90506000805b60045481101561093057600481815481106108ff576108ff6115b9565b9060005260206000200154831061091e5761091b8160016116f7565b91505b806109288161170a565b9150506108e2565b509392505050565b604080516101408101825260008082526020820181905281830181905260608083018290526080830182905260a0830182905260c0830182905260e08301829052610100830182905261012083015291516308c6f12f60e41b8152600481018490529091906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690638c6f12f090602401600060405180830381865afa1580156109ee573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a16919081019061179a565b90506000610a28826101200151610f0e565b5090506001600160a01b0381163014610a5c5760405163b923d26160e01b8152600481018590526024015b60405180910390fd5b5092915050565b610a6b610d01565b80516104b290600490602084019061108b565b6000610a8982610938565b90508060c001516001600160a01b0316336001600160a01b031614610ac0576040516282b42960e81b815260040160405180910390fd5b6000610acf8260c0015161086a565b600084815260086020526040902054909150808211610b0457604051634327880b60e11b815260048101859052602401610a53565b60008481526008602090815260409182902084905581518381529081018490527feb0ebb51128928d7b1a6419c52128a9319bfcb55f0adafea75afbf75f9f2f3e9910160405180910390a150505050565b6000336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610b9f576040516282b42960e81b815260040160405180910390fd5b610ba882610f2f565b610bb457506000919050565b6001806000610bc960e0860160c087016113c3565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254610bf891906116f7565b90915550506040518235907fa0785ec0b9bf31a5475d33c716fb9f500f0ea0bb9e4bc10ec39d5db763c1da1590600090a2506001919050565b600781815481106103c857600080fd5b610c49610d01565b6001600160a01b038116610cae5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a53565b610cb781610ead565b50565b600080610cc683610938565b90506000610cd78260c0015161086a565b600094855260086020526040909420549093119392505050565b600581815481106103c857600080fd5b6000546001600160a01b0316331461078c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a53565b60608151600003610d7a57505060408051602081019091526000815290565b6000604051806060016040528060408152602001611a286040913990506000600384516002610da991906116f7565b610db39190611890565b610dbe9060046118b2565b6001600160401b03811115610dd557610dd5611216565b6040519080825280601f01601f191660200182016040528015610dff576020820181803683370190505b509050600182016020820185865187015b80821015610e6b576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f8116850151845350600183019250610e10565b5050600386510660018114610e875760028114610e9a57610ea2565b603d6001830353603d6002830353610ea2565b603d60018303535b509195945050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000610f0882610f8a565b92915050565b6000606082806020019051810190610f2691906118c9565b91509150915091565b600080610f456102da60e0850160c086016113c3565b905080600003610f67576040516282b42960e81b815260040160405180910390fd5b82356000908152600860205260409020819055610f8383610f95565b9392505050565b6000610f0882610fe5565b6000610fa082610fe5565b610fac57506000919050565b610fbf61028460e0840160c085016113c3565b15610fdd57604051630c59311960e11b815260040160405180910390fd5b506001919050565b600060026000610ffc610100850160e086016113c3565b6001600160a01b0316815260208101919091526040016000205460ff16610fdd576040516282b42960e81b815260040160405180910390fd5b82805482825590600052602060002090810192821561107b579160200282015b8281111561107b578251829061106b9082611968565b5091602001919060010190611055565b506110879291506110d2565b5090565b8280548282559060005260206000209081019282156110c6579160200282015b828111156110c65782518255916020019190600101906110ab565b506110879291506110ef565b808211156110875760006110e68282611104565b506001016110d2565b5b8082111561108757600081556001016110f0565b5080546111109061157f565b6000825580601f10611120575050565b601f016020900490600052602060002090810190610cb791906110ef565b60006020828403121561115057600080fd5b5035919050565b60005b8381101561117257818101518382015260200161115a565b50506000910152565b60008151808452611193816020860160208601611157565b601f01601f19169290920160200192915050565b602081526000610f83602083018461117b565b6001600160a01b0381168114610cb757600080fd5b8015158114610cb757600080fd5b600080604083850312156111f057600080fd5b82356111fb816111ba565b9150602083013561120b816111cf565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60405161014081016001600160401b038111828210171561124f5761124f611216565b60405290565b604051601f8201601f191681016001600160401b038111828210171561127d5761127d611216565b604052919050565b60006001600160401b0382111561129e5761129e611216565b5060051b60200190565b60006001600160401b038211156112c1576112c1611216565b50601f01601f191660200190565b600060208083850312156112e257600080fd5b82356001600160401b03808211156112f957600080fd5b818501915085601f83011261130d57600080fd5b813561132061131b82611285565b611255565b81815260059190911b8301840190848101908883111561133f57600080fd5b8585015b838110156113b65780358581111561135b5760008081fd5b8601603f81018b1361136d5760008081fd5b87810135604061137f61131b836112a8565b8281528d828486010111156113945760008081fd5b828285018c83013760009281018b019290925250845250918601918601611343565b5098975050505050505050565b6000602082840312156113d557600080fd5b8135610f83816111ba565b6000602082840312156113f257600080fd5b81356001600160401b0381111561140857600080fd5b82016101408185031215610f8357600080fd5b6020815281516020820152602082015160408201526000604083015161144c60608401826001600160401b03169052565b5060608301516001600160401b03811660808401525060808301516001600160401b03811660a08401525060a083015160c083015260c083015161149b60e08401826001600160a01b03169052565b5060e08301516101006114b8818501836001600160a01b03169052565b84015190506101206114cd8482018315159052565b8401516101408481015290506114e761016084018261117b565b949350505050565b6000602080838503121561150257600080fd5b82356001600160401b0381111561151857600080fd5b8301601f8101851361152957600080fd5b803561153761131b82611285565b81815260059190911b8201830190838101908783111561155657600080fd5b928401925b828410156115745783358252928401929084019061155b565b979650505050505050565b600181811c9082168061159357607f821691505b6020821081036115b357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b683d913730b6b2911d1160b91b815283516000906115f4816009850160208901611157565b71111610113232b9b1b934b83a34b7b7111d1160711b600991840191820152845161162681601b840160208901611157565b6c1116101134b6b0b3b2911d101160991b601b92909101918201528351611654816028840160208801611157565b61227d60f01b60289290910191820152602a0195945050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152600082516116a881601d850160208701611157565b91909101601d0192915050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610f0857610f086116b5565b6000602082840312156116f057600080fd5b5051919050565b80820180821115610f0857610f086116b5565b60006001820161171c5761171c6116b5565b5060010190565b80516001600160401b038116811461173a57600080fd5b919050565b805161173a816111ba565b805161173a816111cf565b600082601f83011261176657600080fd5b815161177461131b826112a8565b81815284602083860101111561178957600080fd5b6114e7826020830160208701611157565b6000602082840312156117ac57600080fd5b81516001600160401b03808211156117c357600080fd5b9083019061014082860312156117d857600080fd5b6117e061122c565b82518152602083015160208201526117fa60408401611723565b604082015261180b60608401611723565b606082015261181c60808401611723565b608082015260a083015160a082015261183760c0840161173f565b60c082015261184860e0840161173f565b60e082015261010061185b81850161174a565b90820152610120838101518381111561187357600080fd5b61187f88828701611755565b918301919091525095945050505050565b6000826118ad57634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417610f0857610f086116b5565b600080604083850312156118dc57600080fd5b82516118e7816111ba565b60208401519092506001600160401b0381111561190357600080fd5b61190f85828601611755565b9150509250929050565b601f82111561196357600081815260208120601f850160051c810160208610156119405750805b601f850160051c820191505b8181101561195f5782815560010161194c565b5050505b505050565b81516001600160401b0381111561198157611981611216565b6119958161198f845461157f565b84611919565b602080601f8311600181146119ca57600084156119b25750858301515b600019600386901b1c1916600185901b17855561195f565b600085815260208120601f198616915b828110156119f9578886015182559484019460019091019084016119da565b5085821015611a175787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa2646970667358221220c6cd53582319cbc27735f3f52b01120dfa184ec184b0b43dd30fcc9d5d290f5664736f6c63430008130033", - "sourceMap": "890:6033:59:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;658:33:2;;;;;;;;-1:-1:-1;;;;;287:32:61;;;269:51;;257:2;242:18;658:33:2;;;;;;;;1816:31:59;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;923:120:4:-;;;;;;:::i;:::-;;:::i;:::-;;6038:168:59;;;;;;:::i;:::-;;:::i;1224:53::-;;;;;-1:-1:-1;;;;;1224:53:59;;;4722:776;;;;;;:::i;:::-;;:::i;6741:180::-;;;;;;:::i;:::-;;:::i;2159:45::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;5227:25:61;;;5215:2;5200:18;2159:45:59;5081:177:61;6387:152:59;;;;;;:::i;:::-;;:::i;1345:32::-;;;;;;:::i;:::-;;:::i;3200:116:2:-;;;;;;:::i;:::-;-1:-1:-1;;;;;3284:21:2;3261:4;3284:21;;;:15;:21;;;;;;:25;;;3200:116;;;;5776:14:61;;5769:22;5751:41;;5739:2;5724:18;3200:116:2;5611:187:61;1824:101:32;;;:::i;1523:455:2:-;;;;;;:::i;:::-;;:::i;3375:348:59:-;;;;;;:::i;:::-;;:::i;2663:379:2:-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;1201:85:32:-;1247:7;1273:6;-1:-1:-1;;;;;1273:6:32;1201:85;;718:42:4;;;;;;:::i;:::-;;;;;;;;;;;;;;;;5688:155:59;;;;;;:::i;:::-;;:::i;4219:465::-;;;;;;:::i;:::-;;:::i;1032:452:2:-;;;;;;:::i;:::-;;:::i;2074:38:59:-;;;;;;:::i;:::-;;:::i;:198:32:-;;;;;;:::i;:::-;;:::i;3773:269:59:-;;;;;;:::i;:::-;;:::i;1582:35::-;;;;;;:::i;:::-;;:::i;1816:31::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;923:120:4:-;1094:13:32;:11;:13::i;:::-;-1:-1:-1;;;;;1007:20:4;;;::::1;;::::0;;;:10:::1;:20;::::0;;;;:29;;-1:-1:-1;;1007:29:4::1;::::0;::::1;;::::0;;;::::1;::::0;;923:120::o;6038:168:59:-;1094:13:32;:11;:13::i;:::-;6157:42:59;;::::1;::::0;:19:::1;::::0;:42:::1;::::0;::::1;::::0;::::1;:::i;:::-;;6038:168:::0;:::o;4722:776::-;4849:13;4865:15;;;:10;:15;;;;;;4911;:22;;4820:13;;4849;4911:15;4865;;4911:22;;;;;;:::i;:::-;;;;;;;;4890:43;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4943:25;4971:22;4994:5;4971:29;;;;;;;;:::i;:::-;;;;;;;;4943:57;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5010:19;5032;5052:5;5032:26;;;;;;;;:::i;:::-;;;;;;;;5010:48;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5068:26;5097:263;5187:4;5247:11;5309:5;5124:226;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;5097:13;:263::i;:::-;5068:292;;5464:12;5414:63;;;;;;;;:::i;:::-;;;;;;;;;;;;;5371:120;;;;;;;4722:776;;;:::o;6741:180::-;1094:13:32;:11;:13::i;:::-;6866:48:59;;::::1;::::0;:22:::1;::::0;:48:::1;::::0;::::1;::::0;::::1;:::i;6387:152::-:0;1094:13:32;:11;:13::i;:::-;6498:34:59;;::::1;::::0;:15:::1;::::0;:34:::1;::::0;::::1;::::0;::::1;:::i;1345:32::-:0;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1345:32:59;:::o;1824:101:32:-;1094:13;:11;:13::i;:::-;1888:30:::1;1915:1;1888:18;:30::i;:::-;1824:101::o:0;1523:455:2:-;1594:4;1653:10;-1:-1:-1;;;;;1675:8:2;1653:31;;1649:83;;1707:14;;-1:-1:-1;;;1707:14:2;;;;;;;;;;;1649:83;1788:26;1802:11;1788:13;:26::i;:::-;1783:70;;-1:-1:-1;1837:5:2;;1523:455;-1:-1:-1;1523:455:2:o;1783:70::-;1905:1;;1863:38;1879:21;;;;;;;;:::i;:::-;-1:-1:-1;;;;;1863:38:2;-1:-1:-1;;;;;1863:38:2;;;;;;;;;;;;;:43;;;;;;;:::i;:::-;;;;-1:-1:-1;;1922:28:2;;1934:15;;;1922:28;;1934:15;;1922:28;-1:-1:-1;1967:4:2;;1523:455;-1:-1:-1;1523:455:2:o;3375:348:59:-;3465:22;;:37;;-1:-1:-1;;;3465:37:59;;-1:-1:-1;;;;;287:32:61;;;3465:37:59;;;269:51:61;3430:7:59;;;;3465:22;;;:31;;242:18:61;;3465:37:59;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3449:53;;3512:13;3544:9;3539:156;3563:15;:22;3559:26;;3539:156;;;3619:15;3635:1;3619:18;;;;;;;;:::i;:::-;;;;;;;;;3610:5;:27;3606:79;;3665:5;:1;3669;3665:5;:::i;:::-;3657:13;;3606:79;3587:3;;;;:::i;:::-;;;;3539:156;;;-1:-1:-1;3711:5:59;3375:348;-1:-1:-1;;;3375:348:59:o;2663:379:2:-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2789:55:2;;-1:-1:-1;;;2789:55:2;;;;;5227:25:61;;;-1:-1:-1;;;;;;;;2810:8:2;2789:50;;;;5200:18:61;;2789:55:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2789:55:2;;;;;;;;;;;;:::i;:::-;2756:88;;2856:13;2874:33;2890:11;:16;;;2874:15;:33::i;:::-;-1:-1:-1;2855:52:2;-1:-1:-1;;;;;;2922:22:2;;2939:4;2922:22;2918:89;;2967:29;;-1:-1:-1;;;2967:29:2;;;;;5227:25:61;;;5200:18;;2967:29:2;;;;;;;;2918:89;-1:-1:-1;3024:11:2;2663:379;-1:-1:-1;;2663:379:2:o;5688:155:59:-;1094:13:32;:11;:13::i;:::-;5801:35:59;;::::1;::::0;:15:::1;::::0;:35:::1;::::0;::::1;::::0;::::1;:::i;4219:465::-:0;4268:24;4295;4315:3;4295:19;:24::i;:::-;4268:51;;4348:5;:15;;;-1:-1:-1;;;;;4334:29:59;:10;-1:-1:-1;;;;;4334:29:59;;4330:81;;4386:14;;-1:-1:-1;;;4386:14:59;;;;;;;;;;;4330:81;4421:16;4440:27;4451:5;:15;;;4440:10;:27::i;:::-;4478:16;4497:15;;;:10;:15;;;;;;4421:46;;-1:-1:-1;4527:20:59;;;4523:76;;4570:18;;-1:-1:-1;;;4570:18:59;;;;;5227:25:61;;;5200:18;;4570::59;5081:177:61;4523:76:59;4609:15;;;;:10;:15;;;;;;;;;:26;;;4650:27;;14137:25:61;;;14178:18;;;14171:34;;;4650:27:59;;14110:18:61;4650:27:59;;;;;;;4258:426;;;4219:465;:::o;1032:452:2:-;1102:4;1161:10;-1:-1:-1;;;;;1183:8:2;1161:31;;1157:83;;1215:14;;-1:-1:-1;;;1215:14:2;;;;;;;;;;;1157:83;1296:25;1309:11;1296:12;:25::i;:::-;1291:69;;-1:-1:-1;1344:5:2;;1032:452;-1:-1:-1;1032:452:2:o;1291:69::-;1412:1;;1370:38;1386:21;;;;;;;;:::i;:::-;-1:-1:-1;;;;;1370:38:2;-1:-1:-1;;;;;1370:38:2;;;;;;;;;;;;;:43;;;;;;;:::i;:::-;;;;-1:-1:-1;;1429:27:2;;1440:15;;;1429:27;;1440:15;;1429:27;-1:-1:-1;1473:4:2;;1032:452;-1:-1:-1;1032:452:2:o;2074:38:59:-;;;;;;;;;;;;:198:32;1094:13;:11;:13::i;:::-;-1:-1:-1;;;;;2162:22:32;::::1;2154:73;;;::::0;-1:-1:-1;;;2154:73:32;;14418:2:61;2154:73:32::1;::::0;::::1;14400:21:61::0;14457:2;14437:18;;;14430:30;14496:34;14476:18;;;14469:62;-1:-1:-1;;;14547:18:61;;;14540:36;14593:19;;2154:73:32::1;14216:402:61::0;2154:73:32::1;2237:28;2256:8;2237:18;:28::i;:::-;2074:198:::0;:::o;3773:269:59:-;3829:4;3845:24;3872;3892:3;3872:19;:24::i;:::-;3845:51;;3907:16;3926:27;3937:5;:15;;;3926:10;:27::i;:::-;3964:16;3983:15;;;:10;:15;;;;;;;4016:19;;;;3773:269;-1:-1:-1;;;3773:269:59:o;1582:35::-;;;;;;;;;;;;1359:130:32;1247:7;1273:6;-1:-1:-1;;;;;1273:6:32;719:10:37;1422:23:32;1414:68;;;;-1:-1:-1;;;1414:68:32;;14825:2:61;1414:68:32;;;14807:21:61;;;14844:18;;;14837:30;14903:34;14883:18;;;14876:62;14955:18;;1414:68:32;14623:356:61;505:3026:36;563:13;795:4;:11;810:1;795:16;791:31;;-1:-1:-1;;813:9:36;;;;;;;;;-1:-1:-1;813:9:36;;;505:3026::o;791:31::-;872:19;894:6;;;;;;;;;;;;;;;;;872:28;;1303:20;1362:1;1343:4;:11;1357:1;1343:15;;;;:::i;:::-;1342:21;;;;:::i;:::-;1337:27;;:1;:27;:::i;:::-;-1:-1:-1;;;;;1326:39:36;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1326:39:36;;1303:62;;1540:1;1533:5;1529:13;1641:2;1633:6;1629:15;1748:4;1799;1793:11;1787:4;1783:22;1711:1403;1832:6;1823:7;1820:19;1711:1403;;;1934:1;1925:7;1921:15;1910:26;;1972:7;1966:14;2615:4;2607:5;2603:2;2599:14;2595:25;2585:8;2581:40;2575:47;2564:9;2556:67;2668:1;2657:9;2653:17;2640:30;;2758:4;2750:5;2746:2;2742:14;2738:25;2728:8;2724:40;2718:47;2707:9;2699:67;2811:1;2800:9;2796:17;2783:30;;2900:4;2892:5;2889:1;2885:13;2881:24;2871:8;2867:39;2861:46;2850:9;2842:66;2953:1;2942:9;2938:17;2925:30;;3034:4;3027:5;3023:16;3013:8;3009:31;3003:38;2992:9;2984:58;;3087:1;3076:9;3072:17;3059:30;;1711:1403;;;1715:104;;3272:1;3265:4;3259:11;3255:19;3292:1;3287:120;;;;3425:1;3420:71;;;;3248:243;;3287:120;3339:4;3335:1;3324:9;3320:17;3312:32;3388:4;3384:1;3373:9;3369:17;3361:32;3287:120;;3420:71;3472:4;3468:1;3457:9;3453:17;3445:32;3248:243;-1:-1:-1;3518:6:36;;505:3026;-1:-1:-1;;;;;505:3026:36:o;2426:187:32:-;2499:16;2518:6;;-1:-1:-1;;;;;2534:17:32;;;-1:-1:-1;;;;;;2534:17:32;;;;;;2566:40;;2518:6;;;;;;;2566:40;;2499:16;2566:40;2489:124;2426:187;:::o;2999:235:59:-;3168:4;3195:32;3215:11;3195:19;:32::i;:::-;3188:39;2999:235;-1:-1:-1;;2999:235:59:o;176:131:0:-;234:7;243:12;281:4;270:34;;;;;;;;;;;;:::i;:::-;263:41;;;;176:131;;;:::o;2478:483:59:-;2646:4;;2754:33;2765:21;;;;;;;;:::i;2754:33::-;2738:49;;2802:5;2811:1;2802:10;2798:62;;2835:14;;-1:-1:-1;;;2835:14:59;;;;;;;;;;;2798:62;2881:15;;2870:27;;;;:10;:27;;;;;:35;;;2923:31;2881:11;2923:18;:31::i;:::-;2916:38;2478:483;-1:-1:-1;;;2478:483:59:o;744:154:5:-;836:4;859:32;879:11;859:19;:32::i;401:305::-;492:4;513:31;532:11;513:18;:31::i;:::-;508:75;;-1:-1:-1;567:5:5;;401:305;-1:-1:-1;401:305:5:o;508:75::-;597:31;606:21;;;;;;;;:::i;597:31::-;593:85;;;651:16;;-1:-1:-1;;;651:16:5;;;;;;;;;;;593:85;-1:-1:-1;695:4:5;;401:305;-1:-1:-1;401:305:5:o;1465:349:4:-;1557:4;1706:10;:32;1717:20;;;;;;;;:::i;:::-;-1:-1:-1;;;;;1706:32:4;;;;;;;;;;;;-1:-1:-1;1706:32:4;;;;1701:85;;1761:14;;-1:-1:-1;;;1761:14:4;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;:::i;331:180:61:-;390:6;443:2;431:9;422:7;418:23;414:32;411:52;;;459:1;456;449:12;411:52;-1:-1:-1;482:23:61;;331:180;-1:-1:-1;331:180:61:o;516:250::-;601:1;611:113;625:6;622:1;619:13;611:113;;;701:11;;;695:18;682:11;;;675:39;647:2;640:10;611:113;;;-1:-1:-1;;758:1:61;740:16;;733:27;516:250::o;771:271::-;813:3;851:5;845:12;878:6;873:3;866:19;894:76;963:6;956:4;951:3;947:14;940:4;933:5;929:16;894:76;:::i;:::-;1024:2;1003:15;-1:-1:-1;;999:29:61;990:39;;;;1031:4;986:50;;771:271;-1:-1:-1;;771:271:61:o;1047:220::-;1196:2;1185:9;1178:21;1159:4;1216:45;1257:2;1246:9;1242:18;1234:6;1216:45;:::i;1272:131::-;-1:-1:-1;;;;;1347:31:61;;1337:42;;1327:70;;1393:1;1390;1383:12;1408:118;1494:5;1487:13;1480:21;1473:5;1470:32;1460:60;;1516:1;1513;1506:12;1531:382;1596:6;1604;1657:2;1645:9;1636:7;1632:23;1628:32;1625:52;;;1673:1;1670;1663:12;1625:52;1712:9;1699:23;1731:31;1756:5;1731:31;:::i;:::-;1781:5;-1:-1:-1;1838:2:61;1823:18;;1810:32;1851:30;1810:32;1851:30;:::i;:::-;1900:7;1890:17;;;1531:382;;;;;:::o;1918:127::-;1979:10;1974:3;1970:20;1967:1;1960:31;2010:4;2007:1;2000:15;2034:4;2031:1;2024:15;2050:255;2122:2;2116:9;2164:6;2152:19;;-1:-1:-1;;;;;2186:34:61;;2222:22;;;2183:62;2180:88;;;2248:18;;:::i;:::-;2284:2;2277:22;2050:255;:::o;2310:275::-;2381:2;2375:9;2446:2;2427:13;;-1:-1:-1;;2423:27:61;2411:40;;-1:-1:-1;;;;;2466:34:61;;2502:22;;;2463:62;2460:88;;;2528:18;;:::i;:::-;2564:2;2557:22;2310:275;;-1:-1:-1;2310:275:61:o;2590:182::-;2649:4;-1:-1:-1;;;;;2674:6:61;2671:30;2668:56;;;2704:18;;:::i;:::-;-1:-1:-1;2749:1:61;2745:14;2761:4;2741:25;;2590:182::o;2777:187::-;2826:4;-1:-1:-1;;;;;2851:6:61;2848:30;2845:56;;;2881:18;;:::i;:::-;-1:-1:-1;2947:2:61;2926:15;-1:-1:-1;;2922:29:61;2953:4;2918:40;;2777:187::o;2969:1681::-;3063:6;3094:2;3137;3125:9;3116:7;3112:23;3108:32;3105:52;;;3153:1;3150;3143:12;3105:52;3193:9;3180:23;-1:-1:-1;;;;;3263:2:61;3255:6;3252:14;3249:34;;;3279:1;3276;3269:12;3249:34;3317:6;3306:9;3302:22;3292:32;;3362:7;3355:4;3351:2;3347:13;3343:27;3333:55;;3384:1;3381;3374:12;3333:55;3420:2;3407:16;3443:59;3459:42;3498:2;3459:42;:::i;:::-;3443:59;:::i;:::-;3536:15;;;3618:1;3614:10;;;;3606:19;;3602:28;;;3567:12;;;;3642:19;;;3639:39;;;3674:1;3671;3664:12;3639:39;3706:2;3702;3698:11;3718:902;3734:6;3729:3;3726:15;3718:902;;;3820:3;3807:17;3856:2;3843:11;3840:19;3837:109;;;3900:1;3929:2;3925;3918:14;3837:109;3969:20;;4024:2;4016:11;;4012:25;-1:-1:-1;4002:123:61;;4079:1;4108:2;4104;4097:14;4002:123;4169:2;4165;4161:11;4148:25;4196:2;4224:49;4240:32;4269:2;4240:32;:::i;4224:49::-;4300:2;4293:5;4286:17;4344:7;4339:2;4334;4330;4326:11;4322:20;4319:33;4316:126;;;4394:1;4424:3;4419;4412:16;4316:126;4497:2;4492;4488;4484:11;4479:2;4472:5;4468:14;4455:45;4545:1;4524:14;;;4520:23;;4513:34;;;;-1:-1:-1;4560:18:61;;-1:-1:-1;4598:12:61;;;;3751;;3718:902;;;-1:-1:-1;4639:5:61;2969:1681;-1:-1:-1;;;;;;;;2969:1681:61:o;5263:247::-;5322:6;5375:2;5363:9;5354:7;5350:23;5346:32;5343:52;;;5391:1;5388;5381:12;5343:52;5430:9;5417:23;5449:31;5474:5;5449:31;:::i;5803:392::-;5894:6;5947:2;5935:9;5926:7;5922:23;5918:32;5915:52;;;5963:1;5960;5953:12;5915:52;6003:9;5990:23;-1:-1:-1;;;;;6028:6:61;6025:30;6022:50;;;6068:1;6065;6058:12;6022:50;6091:22;;6147:3;6129:16;;;6125:26;6122:46;;;6164:1;6161;6154:12;6307:1292;6496:2;6485:9;6478:21;6541:6;6535:13;6530:2;6519:9;6515:18;6508:41;6603:2;6595:6;6591:15;6585:22;6580:2;6569:9;6565:18;6558:50;6459:4;6655:2;6647:6;6643:15;6637:22;6668:51;6715:2;6704:9;6700:18;6686:12;-1:-1:-1;;;;;6265:30:61;6253:43;;6200:102;6668:51;-1:-1:-1;6768:2:61;6756:15;;6750:22;-1:-1:-1;;;;;6265:30:61;;6830:3;6815:19;;6253:43;-1:-1:-1;6884:3:61;6872:16;;6866:23;-1:-1:-1;;;;;6265:30:61;;6947:3;6932:19;;6253:43;6898:54;7007:3;6999:6;6995:16;6989:23;6983:3;6972:9;6968:19;6961:52;7062:3;7054:6;7050:16;7044:23;7076:55;7126:3;7115:9;7111:19;7095:14;-1:-1:-1;;;;;80:31:61;68:44;;14:104;7076:55;;7180:3;7172:6;7168:16;7162:23;7204:3;7216:54;7266:2;7255:9;7251:18;7235:14;-1:-1:-1;;;;;80:31:61;68:44;;14:104;7216:54;7307:15;;7301:22;;-1:-1:-1;7342:3:61;7354:51;7386:18;;;7301:22;5585:13;5578:21;5566:34;;5515:91;7354:51;7442:15;;7436:22;7477:6;7499:18;;;7492:30;7436:22;-1:-1:-1;7539:54:61;7588:3;7573:19;;7436:22;7539:54;:::i;:::-;7531:62;6307:1292;-1:-1:-1;;;;6307:1292:61:o;7604:890::-;7688:6;7719:2;7762;7750:9;7741:7;7737:23;7733:32;7730:52;;;7778:1;7775;7768:12;7730:52;7818:9;7805:23;-1:-1:-1;;;;;7843:6:61;7840:30;7837:50;;;7883:1;7880;7873:12;7837:50;7906:22;;7959:4;7951:13;;7947:27;-1:-1:-1;7937:55:61;;7988:1;7985;7978:12;7937:55;8024:2;8011:16;8047:59;8063:42;8102:2;8063:42;:::i;8047:59::-;8140:15;;;8222:1;8218:10;;;;8210:19;;8206:28;;;8171:12;;;;8246:19;;;8243:39;;;8278:1;8275;8268:12;8243:39;8302:11;;;;8322:142;8338:6;8333:3;8330:15;8322:142;;;8404:17;;8392:30;;8355:12;;;;8442;;;;8322:142;;;8483:5;7604:890;-1:-1:-1;;;;;;;7604:890:61:o;8499:380::-;8578:1;8574:12;;;;8621;;;8642:61;;8696:4;8688:6;8684:17;8674:27;;8642:61;8749:2;8741:6;8738:14;8718:18;8715:38;8712:161;;8795:10;8790:3;8786:20;8783:1;8776:31;8830:4;8827:1;8820:15;8858:4;8855:1;8848:15;8712:161;;8499:380;;;:::o;8884:127::-;8945:10;8940:3;8936:20;8933:1;8926:31;8976:4;8973:1;8966:15;9000:4;8997:1;8990:15;9016:1386;-1:-1:-1;;;9665:43:61;;9731:13;;9647:3;;9753:74;9731:13;9816:1;9807:11;;9800:4;9788:17;;9753:74;:::i;:::-;-1:-1:-1;;;9886:1:61;9846:16;;;9878:10;;;9871:68;9964:13;;9986:76;9964:13;10048:2;10040:11;;10033:4;10021:17;;9986:76;:::i;:::-;-1:-1:-1;;;10122:2:61;10081:17;;;;10114:11;;;10107:59;10191:13;;10213:76;10191:13;10275:2;10267:11;;10260:4;10248:17;;10213:76;:::i;:::-;-1:-1:-1;;;10349:2:61;10308:17;;;;10341:11;;;10334:35;10393:2;10385:11;;9016:1386;-1:-1:-1;;;;;9016:1386:61:o;10407:461::-;10669:31;10664:3;10657:44;10639:3;10730:6;10724:13;10746:75;10814:6;10809:2;10804:3;10800:12;10793:4;10785:6;10781:17;10746:75;:::i;:::-;10841:16;;;;10859:2;10837:25;;10407:461;-1:-1:-1;;10407:461:61:o;10873:127::-;10934:10;10929:3;10925:20;10922:1;10915:31;10965:4;10962:1;10955:15;10989:4;10986:1;10979:15;11005:128;11072:9;;;11093:11;;;11090:37;;;11107:18;;:::i;11138:184::-;11208:6;11261:2;11249:9;11240:7;11236:23;11232:32;11229:52;;;11277:1;11274;11267:12;11229:52;-1:-1:-1;11300:16:61;;11138:184;-1:-1:-1;11138:184:61:o;11327:125::-;11392:9;;;11413:10;;;11410:36;;;11426:18;;:::i;11457:135::-;11496:3;11517:17;;;11514:43;;11537:18;;:::i;:::-;-1:-1:-1;11584:1:61;11573:13;;11457:135::o;11779:175::-;11857:13;;-1:-1:-1;;;;;11899:30:61;;11889:41;;11879:69;;11944:1;11941;11934:12;11879:69;11779:175;;;:::o;11959:138::-;12038:13;;12060:31;12038:13;12060:31;:::i;12102:132::-;12178:13;;12200:28;12178:13;12200:28;:::i;12239:442::-;12292:5;12345:3;12338:4;12330:6;12326:17;12322:27;12312:55;;12363:1;12360;12353:12;12312:55;12392:6;12386:13;12423:49;12439:32;12468:2;12439:32;:::i;12423:49::-;12497:2;12488:7;12481:19;12543:3;12536:4;12531:2;12523:6;12519:15;12515:26;12512:35;12509:55;;;12560:1;12557;12550:12;12509:55;12573:77;12647:2;12640:4;12631:7;12627:18;12620:4;12612:6;12608:17;12573:77;:::i;12686:1272::-;12786:6;12839:2;12827:9;12818:7;12814:23;12810:32;12807:52;;;12855:1;12852;12845:12;12807:52;12888:9;12882:16;-1:-1:-1;;;;;12958:2:61;12950:6;12947:14;12944:34;;;12974:1;12971;12964:12;12944:34;12997:22;;;;13053:6;13035:16;;;13031:29;13028:49;;;13073:1;13070;13063:12;13028:49;13099:22;;:::i;:::-;13150:2;13144:9;13137:5;13130:24;13200:2;13196;13192:11;13186:18;13181:2;13174:5;13170:14;13163:42;13237:41;13274:2;13270;13266:11;13237:41;:::i;:::-;13232:2;13225:5;13221:14;13214:65;13311:41;13348:2;13344;13340:11;13311:41;:::i;:::-;13306:2;13299:5;13295:14;13288:65;13386:42;13423:3;13419:2;13415:12;13386:42;:::i;:::-;13380:3;13373:5;13369:15;13362:67;13476:3;13472:2;13468:12;13462:19;13456:3;13449:5;13445:15;13438:44;13515:43;13553:3;13549:2;13545:12;13515:43;:::i;:::-;13509:3;13502:5;13498:15;13491:68;13592:43;13630:3;13626:2;13622:12;13592:43;:::i;:::-;13586:3;13579:5;13575:15;13568:68;13655:3;13690:39;13725:2;13721;13717:11;13690:39;:::i;:::-;13674:14;;;13667:63;13749:3;13783:11;;;13777:18;13807:16;;;13804:36;;;13836:1;13833;13826:12;13804:36;13872:55;13919:7;13908:8;13904:2;13900:17;13872:55;:::i;:::-;13856:14;;;13849:79;;;;-1:-1:-1;13860:5:61;12686:1272;-1:-1:-1;;;;;12686:1272:61:o;14984:217::-;15024:1;15050;15040:132;;15094:10;15089:3;15085:20;15082:1;15075:31;15129:4;15126:1;15119:15;15157:4;15154:1;15147:15;15040:132;-1:-1:-1;15186:9:61;;14984:217::o;15206:168::-;15279:9;;;15310;;15327:15;;;15321:22;;15307:37;15297:71;;15348:18;;:::i;15379:471::-;15475:6;15483;15536:2;15524:9;15515:7;15511:23;15507:32;15504:52;;;15552:1;15549;15542:12;15504:52;15584:9;15578:16;15603:31;15628:5;15603:31;:::i;:::-;15702:2;15687:18;;15681:25;15653:5;;-1:-1:-1;;;;;;15718:30:61;;15715:50;;;15761:1;15758;15751:12;15715:50;15784:60;15836:7;15827:6;15816:9;15812:22;15784:60;:::i;:::-;15774:70;;;15379:471;;;;;:::o;15981:545::-;16083:2;16078:3;16075:11;16072:448;;;16119:1;16144:5;16140:2;16133:17;16189:4;16185:2;16175:19;16259:2;16247:10;16243:19;16240:1;16236:27;16230:4;16226:38;16295:4;16283:10;16280:20;16277:47;;;-1:-1:-1;16318:4:61;16277:47;16373:2;16368:3;16364:12;16361:1;16357:20;16351:4;16347:31;16337:41;;16428:82;16446:2;16439:5;16436:13;16428:82;;;16491:17;;;16472:1;16461:13;16428:82;;;16432:3;;;16072:448;15981:545;;;:::o;16702:1352::-;16828:3;16822:10;-1:-1:-1;;;;;16847:6:61;16844:30;16841:56;;;16877:18;;:::i;:::-;16906:97;16996:6;16956:38;16988:4;16982:11;16956:38;:::i;:::-;16950:4;16906:97;:::i;:::-;17058:4;;17122:2;17111:14;;17139:1;17134:663;;;;17841:1;17858:6;17855:89;;;-1:-1:-1;17910:19:61;;;17904:26;17855:89;-1:-1:-1;;16659:1:61;16655:11;;;16651:24;16647:29;16637:40;16683:1;16679:11;;;16634:57;17957:81;;17104:944;;17134:663;15928:1;15921:14;;;15965:4;15952:18;;-1:-1:-1;;17170:20:61;;;17288:236;17302:7;17299:1;17296:14;17288:236;;;17391:19;;;17385:26;17370:42;;17483:27;;;;17451:1;17439:14;;;;17318:19;;17288:236;;;17292:3;17552:6;17543:7;17540:19;17537:201;;;17613:19;;;17607:26;-1:-1:-1;;17696:1:61;17692:14;;;17708:3;17688:24;17684:37;17680:42;17665:58;17650:74;;17537:201;-1:-1:-1;;;;;17784:1:61;17768:14;;;17764:22;17751:36;;-1:-1:-1;16702:1352:61:o", - "linkReferences": {}, - "immutableReferences": { - "125": [ - { - "start": 354, - "length": 32 - }, - { - "start": 1947, - "length": 32 - }, - { - "start": 2471, - "length": 32 - }, - { - "start": 2914, - "length": 32 - } - ] } - }, - "methodIdentifiers": { - "badgeLevel(bytes32)": "42faaa7e", - "badgeLevelDescriptions(uint256)": "d84a4a5e", - "badgeLevelImageURIs(uint256)": "ffa679b7", - "badgeLevelNames(uint256)": "0d713004", - "badgeTokenURI(bytes32)": "24830563", - "canUpgrade(bytes32)": "f942ebd6", - "checkLevel(address)": "8b2c41bc", - "getAndValidateBadge(bytes32)": "8c6f12f0", - "gitcoinPassportDecoder()": "2149ee55", - "hasBadge(address)": "5e50864f", - "isAttester(address)": "b6ebe539", - "issueBadge((bytes32,bytes32,uint64,uint64,uint64,bytes32,address,address,bool,bytes))": "d753a63d", - "levelThresholds(uint256)": "5c445412", - "owner()": "8da5cb5b", - "renounceOwnership()": "715018a6", - "resolver()": "04f3bcec", - "revokeBadge((bytes32,bytes32,uint64,uint64,uint64,bytes32,address,address,bool,bytes))": "8298b030", - "setBadgeLevelDescriptions(string[])": "2c01c7a4", - "setBadgeLevelImageURIs(string[])": "114c05df", - "setBadgeLevelNames(string[])": "43e839cf", - "setLevelThresholds(uint256[])": "bb2ae6bf", - "toggleAttester(address,bool)": "0ee48948", - "transferOwnership(address)": "f2fde38b", - "upgrade(bytes32)": "bc444e13" - }, - "rawMetadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"resolver_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"gitcoinPassportDecoder_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"uid\",\"type\":\"bytes32\"}],\"name\":\"AttestationBadgeMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"uid\",\"type\":\"bytes32\"}],\"name\":\"CannotUpgrade\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SingletonBadge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"uid\",\"type\":\"bytes32\"}],\"name\":\"IssueBadge\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"uid\",\"type\":\"bytes32\"}],\"name\":\"RevokeBadge\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldLevel\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newLevel\",\"type\":\"uint256\"}],\"name\":\"Upgrade\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"badgeLevel\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"badgeLevelDescriptions\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"badgeLevelImageURIs\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"badgeLevelNames\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"uid\",\"type\":\"bytes32\"}],\"name\":\"badgeTokenURI\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"uid\",\"type\":\"bytes32\"}],\"name\":\"canUpgrade\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"checkLevel\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"uid\",\"type\":\"bytes32\"}],\"name\":\"getAndValidateBadge\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"uid\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"schema\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"time\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"expirationTime\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"revocationTime\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"refUID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"attester\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"revocable\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"struct Attestation\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gitcoinPassportDecoder\",\"outputs\":[{\"internalType\":\"contract IGitcoinPassportDecoder\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"hasBadge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isAttester\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"uid\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"schema\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"time\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"expirationTime\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"revocationTime\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"refUID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"attester\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"revocable\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"struct Attestation\",\"name\":\"attestation\",\"type\":\"tuple\"}],\"name\":\"issueBadge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"levelThresholds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"resolver\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"uid\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"schema\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"time\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"expirationTime\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"revocationTime\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"refUID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"attester\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"revocable\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"struct Attestation\",\"name\":\"attestation\",\"type\":\"tuple\"}],\"name\":\"revokeBadge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"badgeLevelDescriptions_\",\"type\":\"string[]\"}],\"name\":\"setBadgeLevelDescriptions\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"badgeLevelImageURIs_\",\"type\":\"string[]\"}],\"name\":\"setBadgeLevelImageURIs\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"badgeLevelNames_\",\"type\":\"string[]\"}],\"name\":\"setBadgeLevelNames\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"levelsThresholds_\",\"type\":\"uint256[]\"}],\"name\":\"setLevelThresholds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"attester\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"enable\",\"type\":\"bool\"}],\"name\":\"toggleAttester\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"uid\",\"type\":\"bytes32\"}],\"name\":\"upgrade\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"events\":{\"Upgrade(uint256,uint256)\":{\"details\":\"Emitted when a badge is upgraded\",\"params\":{\"newLevel\":\"The new badge level\",\"oldLevel\":\"The old badge level\"}}},\"kind\":\"dev\",\"methods\":{\"badgeTokenURI(bytes32)\":{\"params\":{\"uid\":\"The badge UID, or 0x0.\"},\"returns\":{\"_0\":\"The badge token URI (same format as ERC721).\"}},\"canUpgrade(bytes32)\":{\"params\":{\"uid\":\"The unique identifier of the badge.\"},\"returns\":{\"_0\":\"True if the badge can be upgraded, false otherwise.\"}},\"checkLevel(address)\":{\"params\":{\"user\":\"The user address\"},\"returns\":{\"_0\":\"The level of the user's badge\"}},\"getAndValidateBadge(bytes32)\":{\"params\":{\"uid\":\"The attestation UID.\"},\"returns\":{\"_0\":\"The attestation.\"}},\"hasBadge(address)\":{\"params\":{\"user\":\"The user's wallet address.\"},\"returns\":{\"_0\":\"True if the user has one or more of this badge.\"}},\"issueBadge((bytes32,bytes32,uint64,uint64,uint64,bytes32,address,address,bool,bytes))\":{\"params\":{\"attestation\":\"The new attestation.\"},\"returns\":{\"_0\":\"Whether the attestation is valid.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.\"},\"revokeBadge((bytes32,bytes32,uint64,uint64,uint64,bytes32,address,address,bool,bytes))\":{\"params\":{\"attestation\":\"The new attestation.\"},\"returns\":{\"_0\":\"Whether the attestation can be revoked.\"}},\"setBadgeLevelDescriptions(string[])\":{\"details\":\"The length of this array should be levelThresholds.length + 1\",\"params\":{\"badgeLevelDescriptions_\":\"The new badge level descriptions\"}},\"setBadgeLevelImageURIs(string[])\":{\"details\":\"The length of this array should be levelThresholds.length + 1\",\"params\":{\"badgeLevelImageURIs_\":\"The new badge level image URIs\"}},\"setBadgeLevelNames(string[])\":{\"details\":\"The length of this array should be levelThresholds.length + 1\",\"params\":{\"badgeLevelNames_\":\"The new badge level names\"}},\"setLevelThresholds(uint256[])\":{\"details\":\"levelThresholds[0] is the threshold for level 1\",\"params\":{\"levelsThresholds_\":\"The new level thresholds\"}},\"toggleAttester(address,bool)\":{\"params\":{\"attester\":\"The attester address.\",\"enable\":\"True if enable, false if disable.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"upgrade(bytes32)\":{\"details\":\"Only the badge recipient can upgrade their badgeThe new level must be higher than the current level\",\"params\":{\"uid\":\"The unique identifier of the badge.\"}}},\"stateVariables\":{\"badgeLevel\":{\"details\":\"badge UID => current level\"},\"badgeLevelDescriptions\":{\"details\":\"badgeLevelDescriptions[0] is the description for no score, badgeLevelDescriptions[1] is the description for level 1, etc.Therefore this array should have a length of levelThresholds.length + 1\"},\"badgeLevelImageURIs\":{\"details\":\"badgeLevelImageURIs[0] is the URI for no score, badgeLevelImageURIs[1] is the URI for level 1, etc.Therefore this array should have a length of levelThresholds.length + 1\"},\"badgeLevelNames\":{\"details\":\"badgeLevelNames[0] is the name for no score, badgeLevelNames[1] is the name for level 1, etc.Therefore this array should have a length of levelThresholds.length + 1\"},\"levelThresholds\":{\"details\":\"levelThresholds[0] is the threshold for level 1\"}},\"title\":\"PassportScoreScrollBadge\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"badgeTokenURI(bytes32)\":{\"notice\":\"Returns the token URI corresponding to a certain badge UID, or the default badge token URI if the pass UID is 0x0.\"},\"canUpgrade(bytes32)\":{\"notice\":\"Checks if a badge can be upgraded.\"},\"checkLevel(address)\":{\"notice\":\"Check the level of the user's badge\"},\"getAndValidateBadge(bytes32)\":{\"notice\":\"Validate and return a Scroll badge attestation.\"},\"hasBadge(address)\":{\"notice\":\"Returns true if the user has one or more of this badge.\"},\"issueBadge((bytes32,bytes32,uint64,uint64,uint64,bytes32,address,address,bool,bytes))\":{\"notice\":\"A resolver callback invoked in the `issueBadge` function in the parent contract.\"},\"revokeBadge((bytes32,bytes32,uint64,uint64,uint64,bytes32,address,address,bool,bytes))\":{\"notice\":\"A resolver callback invoked in the `revokeBadge` function in the parent contract.\"},\"setBadgeLevelDescriptions(string[])\":{\"notice\":\"Set the badge level descriptions\"},\"setBadgeLevelImageURIs(string[])\":{\"notice\":\"Set the badge level image URIs\"},\"setBadgeLevelNames(string[])\":{\"notice\":\"Set the badge level names\"},\"setLevelThresholds(uint256[])\":{\"notice\":\"Set the level thresholds\"},\"toggleAttester(address,bool)\":{\"notice\":\"Enables or disables a given attester.\"},\"upgrade(bytes32)\":{\"notice\":\"Upgrades a badge.\"}},\"notice\":\"A badge that represents the user's passport score level.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/PassportScoreScrollBadge.sol\":\"PassportScoreScrollBadge\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@canvas/=lib/canvas-contracts/src/\",\":@eas/=node_modules/@ethereum-attestation-service/eas-contracts/\",\":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/\",\":canvas-contracts/=lib/canvas-contracts/\",\":ds-test/=lib/canvas-contracts/lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\",\":openzeppelin/=lib/openzeppelin-contracts/contracts/\",\":solmate/=lib/canvas-contracts/node_modules/solmate/src/\"]},\"sources\":{\"lib/canvas-contracts/src/Common.sol\":{\"keccak256\":\"0x0c5e0fa565efa769b21bd71d86640477679c7606df8381f948ddee83bfc95378\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://f61fde3179f370665a5b9046348b4d3d5af22a905b942520c1c922db9e4f15c5\",\"dweb:/ipfs/QmZREGKUfuUvSRo1C4YgM6BCLrQrKc9jsZEtKEufx3qpPt\"]},\"lib/canvas-contracts/src/Errors.sol\":{\"keccak256\":\"0x303aaebfdda209e07e8857ea25216827286914342cc913c192e5ec7ba42f1294\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://1185fa7c17e059eeb43193f335882aba18ddaee8ad3add6fdb432bf2b88f0d41\",\"dweb:/ipfs/QmaCzcLUHCP3XTveHwRpF3Vws3sHsvxSEWQXkXj4uaLj32\"]},\"lib/canvas-contracts/src/badge/ScrollBadge.sol\":{\"keccak256\":\"0x0ba30ea1859b3b6e6fae765adc5b5152c517ac0646d3c94c9746165f25787e35\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://1d2c1afc23a006e7803630372c15556d70e5d55a4ca05ad2ef823b18fc2c598e\",\"dweb:/ipfs/QmVSmr8xPxyvaEGtVTMYmgXt6rufoyjPgZKKJG5B3Jwoz2\"]},\"lib/canvas-contracts/src/badge/extensions/IScrollBadgeUpgradeable.sol\":{\"keccak256\":\"0x654f5716ecb6247891eedb0e286221684ce4c8b575065618c43a13ff243edeea\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c87333657ae5027ea5b29c38c1434329da7bbe2b2655c4c28f638626a447df2b\",\"dweb:/ipfs/Qmf55af4YqJFk2iCFw37CiCpLtusbbQrVWMHNiDcXD7Mra\"]},\"lib/canvas-contracts/src/badge/extensions/ScrollBadgeAccessControl.sol\":{\"keccak256\":\"0x3b31417b07e86c1eb66b75a382951dc0ba63945f9afc279d12639c84c326e6cc\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a067f720c4735af49fd886f78de625d564adeda00703b0505c916d18f147d283\",\"dweb:/ipfs/QmRL7SsJZiDuR82RLq7VC2qBXH3gHW9JDa7aeYmFa5CWYe\"]},\"lib/canvas-contracts/src/badge/extensions/ScrollBadgeSingleton.sol\":{\"keccak256\":\"0x5484f08d0f09119136f9fb69082682797ec5a985e6d2a89dcbf50f2bc8602cf2\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://2927a7797644fd6a43116a4d8e1eef5639dee03e6a573aaefeca85b0f27b6e40\",\"dweb:/ipfs/QmZMauzNo5JFY5Nq3CfHvaV3XWfQaNvxXD2nD3ZgVeEgpW\"]},\"lib/canvas-contracts/src/interfaces/IScrollBadge.sol\":{\"keccak256\":\"0x2b8514e6c836d5308b43856215c10ffb46ad4d0c4a3615808ff0302661dea671\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://93ae99ac72c267721d58ee2bdf2accfa43834191251f5e9f55d50e64381214e4\",\"dweb:/ipfs/QmWE9ysafKtNcpscSruUSXg7K41wZapLQxgfftMvHkQgXq\"]},\"lib/canvas-contracts/src/interfaces/IScrollBadgeResolver.sol\":{\"keccak256\":\"0xc49a2d5859713f9938ed92593ed005ca07f3b179869aaaa473b960db47568092\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c2387dc24729eabab5db300252746dcf4b2536ed392f4a3a311cbb0f4f7a5dc3\",\"dweb:/ipfs/QmTvBPmyQNT9tNPfa5JkkUbBqHHoi4zEoAoRDHsueQrtHq\"]},\"lib/openzeppelin-contracts/contracts/access/Ownable.sol\":{\"keccak256\":\"0xba43b97fba0d32eb4254f6a5a297b39a19a247082a02d6e69349e071e2946218\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://fc980984badf3984b6303b377711220e067722bbd6a135b24669ff5069ef9f32\",\"dweb:/ipfs/QmPHXMSXj99XjSVM21YsY6aNtLLjLVXDbyN76J5HQYvvrz\"]},\"lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol\":{\"keccak256\":\"0x0705a4b1b86d7b0bd8432118f226ba139c44b9dcaba0a6eafba2dd7d0639c544\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c45b821ef9e882e57c256697a152e108f0f2ad6997609af8904cae99c9bd422e\",\"dweb:/ipfs/QmRKCJW6jjzR5UYZcLpGnhEJ75UVbH6EHkEa49sWx2SKng\"]},\"lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol\":{\"keccak256\":\"0xac6c2efc64baccbde4904ae18ed45139c9aa8cff96d6888344d1e4d2eb8b659f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6e416a280c610b6b7a5f158e4a41aacfaec01ef14d5d1de13b46be9e090265fc\",\"dweb:/ipfs/QmYZP2KrdyccBbhLZT42auhvBTMkwiwUS3V6HWb42rbwbG\"]},\"lib/openzeppelin-contracts/contracts/utils/Address.sol\":{\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://2455248c8ddd9cc6a7af76a13973cddf222072427e7b0e2a7d1aff345145e931\",\"dweb:/ipfs/QmfYjnjRbWqYpuxurqveE6HtzsY1Xx323J428AKQgtBJZm\"]},\"lib/openzeppelin-contracts/contracts/utils/Base64.sol\":{\"keccak256\":\"0x5f3461639fe20794cfb4db4a6d8477388a15b2e70a018043084b7c4bedfa8136\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://77e5309e2cc4cdc3395214edb0ff43ff5a5f7373f5a425383e540f6fab530f96\",\"dweb:/ipfs/QmTV8DZ9knJDa3b5NPBFQqjvTzodyZVjRUg5mx5A99JPLJ\"]},\"lib/openzeppelin-contracts/contracts/utils/Context.sol\":{\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6df0ddf21ce9f58271bdfaa85cde98b200ef242a05a3f85c2bc10a8294800a92\",\"dweb:/ipfs/QmRK2Y5Yc6BK7tGKkgsgn3aJEQGi5aakeSPZvS65PV8Xp3\"]},\"lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol\":{\"keccak256\":\"0xc0e310c163edf15db45d4ff938113ab357f94fa86e61ea8e790853c4d2e13256\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://04db5bc05dcb05ba1f6ca2dfbead17adc8a2e2f911aa80b05e7a36d9eaf96516\",\"dweb:/ipfs/QmVkfHZbXVBUPsTopueCn3qGJX8aEjahFF3Fn4NcygLNm5\"]},\"lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol\":{\"keccak256\":\"0xf09e68aa0dc6722a25bc46490e8d48ed864466d17313b8a0b254c36b54e49899\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://e26daf81e2252dc1fe1ce0e4b55c2eb7c6d1ee84ae6558d1a9554432ea1d32da\",\"dweb:/ipfs/Qmb1UANWiWq5pCKbmHSu772hd4nt374dVaghGmwSVNuk8Q\"]},\"lib/openzeppelin-contracts/contracts/utils/Strings.sol\":{\"keccak256\":\"0x3088eb2868e8d13d89d16670b5f8612c4ab9ff8956272837d8e90106c59c14a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b81d9ff6559ea5c47fc573e17ece6d9ba5d6839e213e6ebc3b4c5c8fe4199d7f\",\"dweb:/ipfs/QmPCW1bFisUzJkyjroY3yipwfism9RRCigCcK1hbXtVM8n\"]},\"lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol\":{\"keccak256\":\"0x809bc3edb4bcbef8263fa616c1b60ee0004b50a8a1bfa164d8f57fd31f520c58\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://8b93a1e39a4a19eba1600b92c96f435442db88cac91e315c8291547a2a7bcfe2\",\"dweb:/ipfs/QmTm34KVe6uZBZwq8dZDNWwPcm24qBJdxqL3rPxBJ4LrMv\"]},\"lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol\":{\"keccak256\":\"0x8432884527a7ad91e6eed1cfc5a0811ae2073e5bca107bd0ca442e9236b03dbd\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://e3aa0eadab7aafcf91a95684765f778f64386f0368de88522ce873c21385278a\",\"dweb:/ipfs/QmPfaVAqWgH1QsT3dHVuL6jwMZbVKdoP8w1PvpiPT2FPWd\"]},\"lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol\":{\"keccak256\":\"0x3af3ca86df39aac39a0514c84459d691434a108d2151c8ce9d69f32e315cab80\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://77d1f1cf302cd5e1dfbbb4ce3b281b28e8c52942d4319fce43df2e1b6f02a52d\",\"dweb:/ipfs/QmT6ZXStmK3Knhh9BokeVHQ9HXTBZNgL3Eb1ar1cYg1hWy\"]},\"lib/openzeppelin-contracts/contracts/utils/math/Math.sol\":{\"keccak256\":\"0xe4455ac1eb7fc497bb7402579e7b4d64d928b846fce7d2b6fde06d366f21c2b3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://cc8841b3cd48ad125e2f46323c8bad3aa0e88e399ec62acb9e57efa7e7c8058c\",\"dweb:/ipfs/QmSqE4mXHA2BXW58deDbXE8MTcsL5JSKNDbm23sVQxRLPS\"]},\"lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol\":{\"keccak256\":\"0xf92515413956f529d95977adc9b0567d583c6203fc31ab1c23824c35187e3ddc\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c50fcc459e49a9858b6d8ad5f911295cb7c9ab57567845a250bf0153f84a95c7\",\"dweb:/ipfs/QmcEW85JRzvDkQggxiBBLVAasXWdkhEysqypj9EaB6H2g6\"]},\"node_modules/@ethereum-attestation-service/eas-contracts/contracts/Common.sol\":{\"keccak256\":\"0x957bd2e6d0d6d637f86208b135c29fbaf4412cb08e5e7a61ede16b80561bf685\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://da1dc9aedbb1d4d39c46c2235918d3adfbc5741dd34a46010cf425d134e7936d\",\"dweb:/ipfs/QmWUk6bXnLaghS2riF3GTFEeURCzgYFMA5woa6AsgPwEgc\"]},\"node_modules/@ethereum-attestation-service/eas-contracts/contracts/EAS.sol\":{\"keccak256\":\"0x0ccad8feb72c73528fddde76e00bd7717233711079e744165e34312169f85684\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://daede3adfe1325b382d2b78dd51ab7ca83c8b1ef86c0e16a1b4d994f4cb36db6\",\"dweb:/ipfs/QmVDMqeTWjMiyaS7TRWYUGurrUEqvqe9YrUnXkM6UvfBFX\"]},\"node_modules/@ethereum-attestation-service/eas-contracts/contracts/IEAS.sol\":{\"keccak256\":\"0x242e0203b314c8539fd4ad3c1f0b7a9c1178fe55b223f4bc007eb9cbf271854c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a3888dc93e93f9f467680f9017bed54a7a4f3b7135cf76a3cbebe96fc263a8c1\",\"dweb:/ipfs/QmSYaJ6oGNw2CocKWSoQnqrpMnD8ag9Gv5hS3U7xnr4Nuv\"]},\"node_modules/@ethereum-attestation-service/eas-contracts/contracts/ISchemaRegistry.sol\":{\"keccak256\":\"0xea97dcd36a0c422169cbaac06698249e199049b627c16bff93fb8ab829058754\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://d453a929ef64a69cd31195ec2ee5ed1193bfa29f633e13c960e92154c37ad158\",\"dweb:/ipfs/QmXs1Z3njbHs2EMgHonrZDfcwdog4kozHY5tYNrhZK5yqz\"]},\"node_modules/@ethereum-attestation-service/eas-contracts/contracts/ISemver.sol\":{\"keccak256\":\"0x04a67939b4e1a8d0a51101b8f69f8882930bbdc66319f38023828625b5d1ff18\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://3dd543fa0e33cef1ea757627f9c2a10a66ee1ce17aa9087f437c5b53a903c7f0\",\"dweb:/ipfs/QmXsy6UsGBzF9zPCCjmiwPpCcX3tHqU13TmR67B69tKnR6\"]},\"node_modules/@ethereum-attestation-service/eas-contracts/contracts/Semver.sol\":{\"keccak256\":\"0xb26a2b03bed18631e2195fa6331167604fdc2672563c4daf87209d07fa1aaaba\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://29c0cd781ce966a19de32c31c72192333b4319539ef169afc168e585a492fbae\",\"dweb:/ipfs/QmTUK1ZUn6cBF7zXB5oT9vUMQ1Sbz9J7ZU91RZJEwsmqX4\"]},\"node_modules/@ethereum-attestation-service/eas-contracts/contracts/eip1271/EIP1271Verifier.sol\":{\"keccak256\":\"0x8a6310b2a5d70bfd849fbf470507a545df5fb4934b59cd95337014ba017e485a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://685b3ed0dbeb7218cc4272af6ea680192418837adeede52c93cd5fc5425f4307\",\"dweb:/ipfs/QmVtExfXou1sz4CneXEwwBAEPFZMo5mk3rmgimBVmqyJou\"]},\"node_modules/@ethereum-attestation-service/eas-contracts/contracts/resolver/ISchemaResolver.sol\":{\"keccak256\":\"0x479f39f03425df5385d790cd2c7447b8250aeb9733d13029d3da8c5982b6604b\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c378654832e0e564f1ef502977253c243712501379ac6233caac05979713ba80\",\"dweb:/ipfs/QmbKdSGgniy45K2vEH93BJtJYo1syp3FL8JCMEUtZELpjx\"]},\"src/IGitcoinPassportDecoder.sol\":{\"keccak256\":\"0x8e9b102a04d11dce84e557b9fed933fa1a21a40729a788a162bf741abf698988\",\"license\":\"GPL\",\"urls\":[\"bzz-raw://b239946b0a81c98562daead880c5ba6973ad05fd2cc29cc7b54be0a51984729a\",\"dweb:/ipfs/QmPNaUppYsXQSUa8MJm5NAWRKcqgNRHvT1PEWxH7RAR5vq\"]},\"src/PassportScoreScrollBadge.sol\":{\"keccak256\":\"0x28e45de5fa53210e5b4e9aaf5c76060546391700e07bc97703344a8adaa0ebe8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://8edda735dea55d3a7304a7bba1c8a9fb438f126ebcd128f31dfaabd0517b4db2\",\"dweb:/ipfs/QmbNhTKjQKDzh8gijcW39acBcv9gd6cPK9HMt52gS9q6Cj\"]}},\"version\":1}", - "metadata": { - "compiler": { - "version": "0.8.19+commit.7dd6d404" - }, - "language": "Solidity", - "output": { - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "resolver_", - "type": "address" - }, - { - "internalType": "address", - "name": "gitcoinPassportDecoder_", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "uid", - "type": "bytes32" - } - ], - "type": "error", - "name": "AttestationBadgeMismatch" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "uid", - "type": "bytes32" - } - ], - "type": "error", - "name": "CannotUpgrade" - }, - { - "inputs": [], - "type": "error", - "name": "SingletonBadge" - }, - { - "inputs": [], - "type": "error", - "name": "Unauthorized" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "uid", - "type": "bytes32", - "indexed": true - } - ], - "type": "event", - "name": "IssueBadge", - "anonymous": false - }, - { - "inputs": [ - { - "internalType": "address", - "name": "previousOwner", - "type": "address", - "indexed": true - }, - { - "internalType": "address", - "name": "newOwner", - "type": "address", - "indexed": true - } - ], - "type": "event", - "name": "OwnershipTransferred", - "anonymous": false - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "uid", - "type": "bytes32", - "indexed": true - } - ], - "type": "event", - "name": "RevokeBadge", - "anonymous": false - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "oldLevel", - "type": "uint256", - "indexed": false - }, - { - "internalType": "uint256", - "name": "newLevel", - "type": "uint256", - "indexed": false - } - ], - "type": "event", - "name": "Upgrade", - "anonymous": false - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function", - "name": "badgeLevel", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ] - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function", - "name": "badgeLevelDescriptions", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ] - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function", - "name": "badgeLevelImageURIs", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ] - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function", - "name": "badgeLevelNames", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ] - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "uid", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function", - "name": "badgeTokenURI", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ] - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "uid", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function", - "name": "canUpgrade", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ] - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function", - "name": "checkLevel", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ] - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "uid", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function", - "name": "getAndValidateBadge", - "outputs": [ - { - "internalType": "struct Attestation", - "name": "", - "type": "tuple", - "components": [ - { - "internalType": "bytes32", - "name": "uid", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "schema", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "time", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "expirationTime", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "revocationTime", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "refUID", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "address", - "name": "attester", - "type": "address" - }, - { - "internalType": "bool", - "name": "revocable", - "type": "bool" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ] - } - ] - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "gitcoinPassportDecoder", - "outputs": [ - { - "internalType": "contract IGitcoinPassportDecoder", - "name": "", - "type": "address" - } - ] - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function", - "name": "hasBadge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ] - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function", - "name": "isAttester", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ] - }, - { - "inputs": [ - { - "internalType": "struct Attestation", - "name": "attestation", - "type": "tuple", - "components": [ - { - "internalType": "bytes32", - "name": "uid", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "schema", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "time", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "expirationTime", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "revocationTime", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "refUID", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "address", - "name": "attester", - "type": "address" - }, - { - "internalType": "bool", - "name": "revocable", - "type": "bool" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ] - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "issueBadge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ] - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function", - "name": "levelThresholds", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ] - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ] - }, - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "function", - "name": "renounceOwnership" - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "resolver", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ] - }, - { - "inputs": [ - { - "internalType": "struct Attestation", - "name": "attestation", - "type": "tuple", - "components": [ - { - "internalType": "bytes32", - "name": "uid", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "schema", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "time", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "expirationTime", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "revocationTime", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "refUID", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "address", - "name": "attester", - "type": "address" - }, - { - "internalType": "bool", - "name": "revocable", - "type": "bool" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ] - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "revokeBadge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ] - }, - { - "inputs": [ - { - "internalType": "string[]", - "name": "badgeLevelDescriptions_", - "type": "string[]" - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "setBadgeLevelDescriptions" - }, - { - "inputs": [ - { - "internalType": "string[]", - "name": "badgeLevelImageURIs_", - "type": "string[]" - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "setBadgeLevelImageURIs" - }, - { - "inputs": [ - { - "internalType": "string[]", - "name": "badgeLevelNames_", - "type": "string[]" - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "setBadgeLevelNames" - }, - { - "inputs": [ - { - "internalType": "uint256[]", - "name": "levelsThresholds_", - "type": "uint256[]" - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "setLevelThresholds" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "attester", - "type": "address" - }, - { - "internalType": "bool", - "name": "enable", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "toggleAttester" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "transferOwnership" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "uid", - "type": "bytes32" - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "upgrade" - } - ], - "devdoc": { - "kind": "dev", - "methods": { - "badgeTokenURI(bytes32)": { - "params": { - "uid": "The badge UID, or 0x0." - }, - "returns": { - "_0": "The badge token URI (same format as ERC721)." - } - }, - "canUpgrade(bytes32)": { - "params": { - "uid": "The unique identifier of the badge." - }, - "returns": { - "_0": "True if the badge can be upgraded, false otherwise." - } - }, - "checkLevel(address)": { - "params": { - "user": "The user address" - }, - "returns": { - "_0": "The level of the user's badge" - } - }, - "getAndValidateBadge(bytes32)": { - "params": { - "uid": "The attestation UID." - }, - "returns": { - "_0": "The attestation." - } - }, - "hasBadge(address)": { - "params": { - "user": "The user's wallet address." - }, - "returns": { - "_0": "True if the user has one or more of this badge." - } - }, - "issueBadge((bytes32,bytes32,uint64,uint64,uint64,bytes32,address,address,bool,bytes))": { - "params": { - "attestation": "The new attestation." - }, - "returns": { - "_0": "Whether the attestation is valid." - } - }, - "owner()": { - "details": "Returns the address of the current owner." - }, - "renounceOwnership()": { - "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner." - }, - "revokeBadge((bytes32,bytes32,uint64,uint64,uint64,bytes32,address,address,bool,bytes))": { - "params": { - "attestation": "The new attestation." - }, - "returns": { - "_0": "Whether the attestation can be revoked." - } - }, - "setBadgeLevelDescriptions(string[])": { - "details": "The length of this array should be levelThresholds.length + 1", - "params": { - "badgeLevelDescriptions_": "The new badge level descriptions" - } - }, - "setBadgeLevelImageURIs(string[])": { - "details": "The length of this array should be levelThresholds.length + 1", - "params": { - "badgeLevelImageURIs_": "The new badge level image URIs" - } - }, - "setBadgeLevelNames(string[])": { - "details": "The length of this array should be levelThresholds.length + 1", - "params": { - "badgeLevelNames_": "The new badge level names" - } - }, - "setLevelThresholds(uint256[])": { - "details": "levelThresholds[0] is the threshold for level 1", - "params": { - "levelsThresholds_": "The new level thresholds" - } - }, - "toggleAttester(address,bool)": { - "params": { - "attester": "The attester address.", - "enable": "True if enable, false if disable." - } - }, - "transferOwnership(address)": { - "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." - }, - "upgrade(bytes32)": { - "details": "Only the badge recipient can upgrade their badgeThe new level must be higher than the current level", - "params": { - "uid": "The unique identifier of the badge." - } - } - }, - "version": 1 - }, - "userdoc": { - "kind": "user", - "methods": { - "badgeTokenURI(bytes32)": { - "notice": "Returns the token URI corresponding to a certain badge UID, or the default badge token URI if the pass UID is 0x0." - }, - "canUpgrade(bytes32)": { - "notice": "Checks if a badge can be upgraded." - }, - "checkLevel(address)": { - "notice": "Check the level of the user's badge" - }, - "getAndValidateBadge(bytes32)": { - "notice": "Validate and return a Scroll badge attestation." - }, - "hasBadge(address)": { - "notice": "Returns true if the user has one or more of this badge." - }, - "issueBadge((bytes32,bytes32,uint64,uint64,uint64,bytes32,address,address,bool,bytes))": { - "notice": "A resolver callback invoked in the `issueBadge` function in the parent contract." - }, - "revokeBadge((bytes32,bytes32,uint64,uint64,uint64,bytes32,address,address,bool,bytes))": { - "notice": "A resolver callback invoked in the `revokeBadge` function in the parent contract." - }, - "setBadgeLevelDescriptions(string[])": { - "notice": "Set the badge level descriptions" - }, - "setBadgeLevelImageURIs(string[])": { - "notice": "Set the badge level image URIs" - }, - "setBadgeLevelNames(string[])": { - "notice": "Set the badge level names" - }, - "setLevelThresholds(uint256[])": { - "notice": "Set the level thresholds" - }, - "toggleAttester(address,bool)": { - "notice": "Enables or disables a given attester." - }, - "upgrade(bytes32)": { - "notice": "Upgrades a badge." - } - }, - "version": 1 - } - }, - "settings": { - "remappings": [ - "@canvas/=lib/canvas-contracts/src/", - "@eas/=node_modules/@ethereum-attestation-service/eas-contracts/", - "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", - "canvas-contracts/=lib/canvas-contracts/", - "ds-test/=lib/canvas-contracts/lib/forge-std/lib/ds-test/src/", - "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", - "forge-std/=lib/forge-std/src/", - "openzeppelin-contracts/=lib/openzeppelin-contracts/", - "openzeppelin/=lib/openzeppelin-contracts/contracts/", - "solmate/=lib/canvas-contracts/node_modules/solmate/src/" - ], - "optimizer": { - "enabled": true, - "runs": 200 - }, - "metadata": { - "bytecodeHash": "ipfs" - }, - "compilationTarget": { - "src/PassportScoreScrollBadge.sol": "PassportScoreScrollBadge" - }, - "evmVersion": "paris", - "libraries": {} - }, - "sources": { - "lib/canvas-contracts/src/Common.sol": { - "keccak256": "0x0c5e0fa565efa769b21bd71d86640477679c7606df8381f948ddee83bfc95378", - "urls": [ - "bzz-raw://f61fde3179f370665a5b9046348b4d3d5af22a905b942520c1c922db9e4f15c5", - "dweb:/ipfs/QmZREGKUfuUvSRo1C4YgM6BCLrQrKc9jsZEtKEufx3qpPt" - ], - "license": "MIT" - }, - "lib/canvas-contracts/src/Errors.sol": { - "keccak256": "0x303aaebfdda209e07e8857ea25216827286914342cc913c192e5ec7ba42f1294", - "urls": [ - "bzz-raw://1185fa7c17e059eeb43193f335882aba18ddaee8ad3add6fdb432bf2b88f0d41", - "dweb:/ipfs/QmaCzcLUHCP3XTveHwRpF3Vws3sHsvxSEWQXkXj4uaLj32" - ], - "license": "MIT" - }, - "lib/canvas-contracts/src/badge/ScrollBadge.sol": { - "keccak256": "0x0ba30ea1859b3b6e6fae765adc5b5152c517ac0646d3c94c9746165f25787e35", - "urls": [ - "bzz-raw://1d2c1afc23a006e7803630372c15556d70e5d55a4ca05ad2ef823b18fc2c598e", - "dweb:/ipfs/QmVSmr8xPxyvaEGtVTMYmgXt6rufoyjPgZKKJG5B3Jwoz2" - ], - "license": "MIT" - }, - "lib/canvas-contracts/src/badge/extensions/IScrollBadgeUpgradeable.sol": { - "keccak256": "0x654f5716ecb6247891eedb0e286221684ce4c8b575065618c43a13ff243edeea", - "urls": [ - "bzz-raw://c87333657ae5027ea5b29c38c1434329da7bbe2b2655c4c28f638626a447df2b", - "dweb:/ipfs/Qmf55af4YqJFk2iCFw37CiCpLtusbbQrVWMHNiDcXD7Mra" - ], - "license": "MIT" - }, - "lib/canvas-contracts/src/badge/extensions/ScrollBadgeAccessControl.sol": { - "keccak256": "0x3b31417b07e86c1eb66b75a382951dc0ba63945f9afc279d12639c84c326e6cc", - "urls": [ - "bzz-raw://a067f720c4735af49fd886f78de625d564adeda00703b0505c916d18f147d283", - "dweb:/ipfs/QmRL7SsJZiDuR82RLq7VC2qBXH3gHW9JDa7aeYmFa5CWYe" - ], - "license": "MIT" - }, - "lib/canvas-contracts/src/badge/extensions/ScrollBadgeSingleton.sol": { - "keccak256": "0x5484f08d0f09119136f9fb69082682797ec5a985e6d2a89dcbf50f2bc8602cf2", - "urls": [ - "bzz-raw://2927a7797644fd6a43116a4d8e1eef5639dee03e6a573aaefeca85b0f27b6e40", - "dweb:/ipfs/QmZMauzNo5JFY5Nq3CfHvaV3XWfQaNvxXD2nD3ZgVeEgpW" - ], - "license": "MIT" - }, - "lib/canvas-contracts/src/interfaces/IScrollBadge.sol": { - "keccak256": "0x2b8514e6c836d5308b43856215c10ffb46ad4d0c4a3615808ff0302661dea671", - "urls": [ - "bzz-raw://93ae99ac72c267721d58ee2bdf2accfa43834191251f5e9f55d50e64381214e4", - "dweb:/ipfs/QmWE9ysafKtNcpscSruUSXg7K41wZapLQxgfftMvHkQgXq" - ], - "license": "MIT" - }, - "lib/canvas-contracts/src/interfaces/IScrollBadgeResolver.sol": { - "keccak256": "0xc49a2d5859713f9938ed92593ed005ca07f3b179869aaaa473b960db47568092", - "urls": [ - "bzz-raw://c2387dc24729eabab5db300252746dcf4b2536ed392f4a3a311cbb0f4f7a5dc3", - "dweb:/ipfs/QmTvBPmyQNT9tNPfa5JkkUbBqHHoi4zEoAoRDHsueQrtHq" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts/contracts/access/Ownable.sol": { - "keccak256": "0xba43b97fba0d32eb4254f6a5a297b39a19a247082a02d6e69349e071e2946218", - "urls": [ - "bzz-raw://fc980984badf3984b6303b377711220e067722bbd6a135b24669ff5069ef9f32", - "dweb:/ipfs/QmPHXMSXj99XjSVM21YsY6aNtLLjLVXDbyN76J5HQYvvrz" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol": { - "keccak256": "0x0705a4b1b86d7b0bd8432118f226ba139c44b9dcaba0a6eafba2dd7d0639c544", - "urls": [ - "bzz-raw://c45b821ef9e882e57c256697a152e108f0f2ad6997609af8904cae99c9bd422e", - "dweb:/ipfs/QmRKCJW6jjzR5UYZcLpGnhEJ75UVbH6EHkEa49sWx2SKng" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol": { - "keccak256": "0xac6c2efc64baccbde4904ae18ed45139c9aa8cff96d6888344d1e4d2eb8b659f", - "urls": [ - "bzz-raw://6e416a280c610b6b7a5f158e4a41aacfaec01ef14d5d1de13b46be9e090265fc", - "dweb:/ipfs/QmYZP2KrdyccBbhLZT42auhvBTMkwiwUS3V6HWb42rbwbG" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts/contracts/utils/Address.sol": { - "keccak256": "0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa", - "urls": [ - "bzz-raw://2455248c8ddd9cc6a7af76a13973cddf222072427e7b0e2a7d1aff345145e931", - "dweb:/ipfs/QmfYjnjRbWqYpuxurqveE6HtzsY1Xx323J428AKQgtBJZm" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts/contracts/utils/Base64.sol": { - "keccak256": "0x5f3461639fe20794cfb4db4a6d8477388a15b2e70a018043084b7c4bedfa8136", - "urls": [ - "bzz-raw://77e5309e2cc4cdc3395214edb0ff43ff5a5f7373f5a425383e540f6fab530f96", - "dweb:/ipfs/QmTV8DZ9knJDa3b5NPBFQqjvTzodyZVjRUg5mx5A99JPLJ" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts/contracts/utils/Context.sol": { - "keccak256": "0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7", - "urls": [ - "bzz-raw://6df0ddf21ce9f58271bdfaa85cde98b200ef242a05a3f85c2bc10a8294800a92", - "dweb:/ipfs/QmRK2Y5Yc6BK7tGKkgsgn3aJEQGi5aakeSPZvS65PV8Xp3" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol": { - "keccak256": "0xc0e310c163edf15db45d4ff938113ab357f94fa86e61ea8e790853c4d2e13256", - "urls": [ - "bzz-raw://04db5bc05dcb05ba1f6ca2dfbead17adc8a2e2f911aa80b05e7a36d9eaf96516", - "dweb:/ipfs/QmVkfHZbXVBUPsTopueCn3qGJX8aEjahFF3Fn4NcygLNm5" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol": { - "keccak256": "0xf09e68aa0dc6722a25bc46490e8d48ed864466d17313b8a0b254c36b54e49899", - "urls": [ - "bzz-raw://e26daf81e2252dc1fe1ce0e4b55c2eb7c6d1ee84ae6558d1a9554432ea1d32da", - "dweb:/ipfs/Qmb1UANWiWq5pCKbmHSu772hd4nt374dVaghGmwSVNuk8Q" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts/contracts/utils/Strings.sol": { - "keccak256": "0x3088eb2868e8d13d89d16670b5f8612c4ab9ff8956272837d8e90106c59c14a0", - "urls": [ - "bzz-raw://b81d9ff6559ea5c47fc573e17ece6d9ba5d6839e213e6ebc3b4c5c8fe4199d7f", - "dweb:/ipfs/QmPCW1bFisUzJkyjroY3yipwfism9RRCigCcK1hbXtVM8n" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol": { - "keccak256": "0x809bc3edb4bcbef8263fa616c1b60ee0004b50a8a1bfa164d8f57fd31f520c58", - "urls": [ - "bzz-raw://8b93a1e39a4a19eba1600b92c96f435442db88cac91e315c8291547a2a7bcfe2", - "dweb:/ipfs/QmTm34KVe6uZBZwq8dZDNWwPcm24qBJdxqL3rPxBJ4LrMv" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol": { - "keccak256": "0x8432884527a7ad91e6eed1cfc5a0811ae2073e5bca107bd0ca442e9236b03dbd", - "urls": [ - "bzz-raw://e3aa0eadab7aafcf91a95684765f778f64386f0368de88522ce873c21385278a", - "dweb:/ipfs/QmPfaVAqWgH1QsT3dHVuL6jwMZbVKdoP8w1PvpiPT2FPWd" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol": { - "keccak256": "0x3af3ca86df39aac39a0514c84459d691434a108d2151c8ce9d69f32e315cab80", - "urls": [ - "bzz-raw://77d1f1cf302cd5e1dfbbb4ce3b281b28e8c52942d4319fce43df2e1b6f02a52d", - "dweb:/ipfs/QmT6ZXStmK3Knhh9BokeVHQ9HXTBZNgL3Eb1ar1cYg1hWy" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts/contracts/utils/math/Math.sol": { - "keccak256": "0xe4455ac1eb7fc497bb7402579e7b4d64d928b846fce7d2b6fde06d366f21c2b3", - "urls": [ - "bzz-raw://cc8841b3cd48ad125e2f46323c8bad3aa0e88e399ec62acb9e57efa7e7c8058c", - "dweb:/ipfs/QmSqE4mXHA2BXW58deDbXE8MTcsL5JSKNDbm23sVQxRLPS" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol": { - "keccak256": "0xf92515413956f529d95977adc9b0567d583c6203fc31ab1c23824c35187e3ddc", - "urls": [ - "bzz-raw://c50fcc459e49a9858b6d8ad5f911295cb7c9ab57567845a250bf0153f84a95c7", - "dweb:/ipfs/QmcEW85JRzvDkQggxiBBLVAasXWdkhEysqypj9EaB6H2g6" - ], - "license": "MIT" - }, - "node_modules/@ethereum-attestation-service/eas-contracts/contracts/Common.sol": { - "keccak256": "0x957bd2e6d0d6d637f86208b135c29fbaf4412cb08e5e7a61ede16b80561bf685", - "urls": [ - "bzz-raw://da1dc9aedbb1d4d39c46c2235918d3adfbc5741dd34a46010cf425d134e7936d", - "dweb:/ipfs/QmWUk6bXnLaghS2riF3GTFEeURCzgYFMA5woa6AsgPwEgc" - ], - "license": "MIT" - }, - "node_modules/@ethereum-attestation-service/eas-contracts/contracts/EAS.sol": { - "keccak256": "0x0ccad8feb72c73528fddde76e00bd7717233711079e744165e34312169f85684", - "urls": [ - "bzz-raw://daede3adfe1325b382d2b78dd51ab7ca83c8b1ef86c0e16a1b4d994f4cb36db6", - "dweb:/ipfs/QmVDMqeTWjMiyaS7TRWYUGurrUEqvqe9YrUnXkM6UvfBFX" - ], - "license": "MIT" - }, - "node_modules/@ethereum-attestation-service/eas-contracts/contracts/IEAS.sol": { - "keccak256": "0x242e0203b314c8539fd4ad3c1f0b7a9c1178fe55b223f4bc007eb9cbf271854c", - "urls": [ - "bzz-raw://a3888dc93e93f9f467680f9017bed54a7a4f3b7135cf76a3cbebe96fc263a8c1", - "dweb:/ipfs/QmSYaJ6oGNw2CocKWSoQnqrpMnD8ag9Gv5hS3U7xnr4Nuv" - ], - "license": "MIT" - }, - "node_modules/@ethereum-attestation-service/eas-contracts/contracts/ISchemaRegistry.sol": { - "keccak256": "0xea97dcd36a0c422169cbaac06698249e199049b627c16bff93fb8ab829058754", - "urls": [ - "bzz-raw://d453a929ef64a69cd31195ec2ee5ed1193bfa29f633e13c960e92154c37ad158", - "dweb:/ipfs/QmXs1Z3njbHs2EMgHonrZDfcwdog4kozHY5tYNrhZK5yqz" - ], - "license": "MIT" - }, - "node_modules/@ethereum-attestation-service/eas-contracts/contracts/ISemver.sol": { - "keccak256": "0x04a67939b4e1a8d0a51101b8f69f8882930bbdc66319f38023828625b5d1ff18", - "urls": [ - "bzz-raw://3dd543fa0e33cef1ea757627f9c2a10a66ee1ce17aa9087f437c5b53a903c7f0", - "dweb:/ipfs/QmXsy6UsGBzF9zPCCjmiwPpCcX3tHqU13TmR67B69tKnR6" - ], - "license": "MIT" - }, - "node_modules/@ethereum-attestation-service/eas-contracts/contracts/Semver.sol": { - "keccak256": "0xb26a2b03bed18631e2195fa6331167604fdc2672563c4daf87209d07fa1aaaba", - "urls": [ - "bzz-raw://29c0cd781ce966a19de32c31c72192333b4319539ef169afc168e585a492fbae", - "dweb:/ipfs/QmTUK1ZUn6cBF7zXB5oT9vUMQ1Sbz9J7ZU91RZJEwsmqX4" - ], - "license": "MIT" - }, - "node_modules/@ethereum-attestation-service/eas-contracts/contracts/eip1271/EIP1271Verifier.sol": { - "keccak256": "0x8a6310b2a5d70bfd849fbf470507a545df5fb4934b59cd95337014ba017e485a", - "urls": [ - "bzz-raw://685b3ed0dbeb7218cc4272af6ea680192418837adeede52c93cd5fc5425f4307", - "dweb:/ipfs/QmVtExfXou1sz4CneXEwwBAEPFZMo5mk3rmgimBVmqyJou" - ], - "license": "MIT" - }, - "node_modules/@ethereum-attestation-service/eas-contracts/contracts/resolver/ISchemaResolver.sol": { - "keccak256": "0x479f39f03425df5385d790cd2c7447b8250aeb9733d13029d3da8c5982b6604b", - "urls": [ - "bzz-raw://c378654832e0e564f1ef502977253c243712501379ac6233caac05979713ba80", - "dweb:/ipfs/QmbKdSGgniy45K2vEH93BJtJYo1syp3FL8JCMEUtZELpjx" - ], - "license": "MIT" - }, - "src/IGitcoinPassportDecoder.sol": { - "keccak256": "0x8e9b102a04d11dce84e557b9fed933fa1a21a40729a788a162bf741abf698988", - "urls": [ - "bzz-raw://b239946b0a81c98562daead880c5ba6973ad05fd2cc29cc7b54be0a51984729a", - "dweb:/ipfs/QmPNaUppYsXQSUa8MJm5NAWRKcqgNRHvT1PEWxH7RAR5vq" - ], - "license": "GPL" - }, - "src/PassportScoreScrollBadge.sol": { - "keccak256": "0x28e45de5fa53210e5b4e9aaf5c76060546391700e07bc97703344a8adaa0ebe8", - "urls": [ - "bzz-raw://8edda735dea55d3a7304a7bba1c8a9fb438f126ebcd128f31dfaabd0517b4db2", - "dweb:/ipfs/QmbNhTKjQKDzh8gijcW39acBcv9gd6cPK9HMt52gS9q6Cj" - ], - "license": "MIT" - } - }, - "version": 1 - }, - "id": 59 + ] } diff --git a/app/abi/ScrollCanvasProfileRegistry.json b/app/abi/ScrollCanvasProfileRegistry.json new file mode 100644 index 0000000000..2677717a42 --- /dev/null +++ b/app/abi/ScrollCanvasProfileRegistry.json @@ -0,0 +1,42 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getProfile", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isProfileMinted", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ] +} diff --git a/app/components/ScrollCampaign.tsx b/app/components/ScrollCampaign.tsx index 285d621dea..a19ab62921 100644 --- a/app/components/ScrollCampaign.tsx +++ b/app/components/ScrollCampaign.tsx @@ -1,17 +1,15 @@ -import React, { useEffect, useContext, useMemo, useState } from "react"; +import React, { useEffect, useContext } from "react"; import NotFound from "../pages/NotFound"; import { useLoginFlow } from "../hooks/useLoginFlow"; import { LoadButton } from "./LoadButton"; import { useNextCampaignStep, useNavigateToRootStep } from "../hooks/useNextCampaignStep"; import { useDatastoreConnectionContext } from "../context/datastoreConnectionContext"; import { CeramicContext } from "../context/ceramicContext"; -import { PROVIDER_ID, Passport } from "@gitcoin/passport-types"; +import { PROVIDER_ID } from "@gitcoin/passport-types"; import { useSetCustomizationKey } from "../hooks/useCustomization"; -import { scrollCampaignBadgeProviders } from "../config/scroll_campaign"; import { ScrollCampaignPage } from "./scroll/ScrollCampaignPage"; import { ScrollConnectGithub } from "./scroll/ScrollConnectGithub"; import { ScrollMintBadge } from "./scroll/ScrollMintPage"; -import { ScrollMintingBadge } from "./scroll/ScrollMintingBadge"; import { ScrollMintedBadge } from "./scroll/ScrollMintedBadge"; import { useMintBadge } from "../hooks/useMintBadge"; @@ -25,12 +23,6 @@ export interface ProviderWithTitle extends Provider { title: string; } -interface TopBadges { - title: string; - level: number; - image: string; -} - const ScrollLogin = () => { const nextStep = useNextCampaignStep(); const { isLoggingIn, signIn, loginStep } = useLoginFlow({ onLoggedIn: nextStep }); @@ -80,7 +72,7 @@ export const ScrollCampaign = ({ step }: { step: number }) => { const { did, dbAccessToken } = useDatastoreConnectionContext(); const { database } = useContext(CeramicContext); - const { onMint, syncingToChain, earnedBadges, badgesFreshlyMinted } = useMintBadge(); + const { onMint, syncingToChain, badgesFreshlyMinted } = useMintBadge(); useEffect(() => { setCustomizationKey("scroll"); @@ -91,30 +83,14 @@ export const ScrollCampaign = ({ step }: { step: number }) => { console.log("Access token or did are not present. Going back to login step!"); goToLoginStep(); } - }, [dbAccessToken, did, step, goToLoginStep]); - - const [passport, setPassport] = useState(undefined); - - const badgeStamps = useMemo( - () => (passport ? passport.stamps.filter(({ provider }) => scrollCampaignBadgeProviders.includes(provider)) : []), - [passport] - ); - - const deduplicatedBadgeStamps = useMemo( - // TODO Deduplicate by seeing if in burnedHashes but not user's hashes - () => badgeStamps.filter(({ provider }) => true), - [badgeStamps] - ); + }, [dbAccessToken, did, step, goToLoginStep, database]); if (step === 0) { return ; } else if (step === 1) { return ; } else if (step === 2) { - if (syncingToChain) { - return ; - } - return ; + return ; } else if (step === 3) { return ; } diff --git a/app/components/scroll/ScrollConnectGithub.tsx b/app/components/scroll/ScrollConnectGithub.tsx index 29b57c3808..7b481edeff 100644 --- a/app/components/scroll/ScrollConnectGithub.tsx +++ b/app/components/scroll/ScrollConnectGithub.tsx @@ -16,7 +16,6 @@ import { datadogLogs } from "@datadog/browser-logs"; import { LoadButton } from "../LoadButton"; import { GitHubIcon } from "../WelcomeFooter"; import { ScrollCampaignPage } from "./ScrollCampaignPage"; -import { useScrollStampsStore } from "../../context/scrollCampaignStore"; export const ScrollConnectGithub = () => { const goToNextStep = useNextCampaignStep(); @@ -29,7 +28,6 @@ export const ScrollConnectGithub = () => { const [msg, setMsg] = useState("Verifying existing badges on chain ... "); const [isVerificationRunning, setIsVerificationRunning] = useState(false); const { failure } = useMessage(); - const { setCredentials } = useScrollStampsStore(); const { areBadgesLoading, hasAtLeastOneBadge } = useScrollBadge(address); @@ -111,7 +109,6 @@ export const ScrollConnectGithub = () => { }); } - setCredentials(verifiedCredentials); goToNextStep(); } else { setNoCredentialReceived(true); @@ -120,39 +117,35 @@ export const ScrollConnectGithub = () => { } finally { setIsVerificationRunning(false); } - }, [did, address, checkSessionIsValid, goToLoginStep, goToNextStep, userDid]); + }, [did, address, checkSessionIsValid, goToLoginStep, goToNextStep, userDid, database, failure]); - const body = noCredentialReceived ? ( - <> -
We're sorry!
-
You do not qualify because you do not have the minimum 10 contributions needed.
- - ) : ( - <> -
Connect to Github
-
- Passport is privacy preserving and verifies you have 1 or more commits to the following Repos located here. - Click below and obtain the specific developer credentials -
-
- - {msg ? msg : "Connect to Github"} - -
- - ); return ( -
{body}
-
-
-
+ {noCredentialReceived ? ( + <> +
We're sorry!
+
You do not qualify because you do not have the minimum 10 contributions needed.
+ + ) : ( + <> +
Connect to Github
+
+ Passport is privacy preserving and verifies you have 1 or more commits to the following Repos located here. + Click below and obtain the specific developer credentials +
+
+ + {msg ? msg : "Connect to Github"} + +
+ + )}
); }; diff --git a/app/components/scroll/ScrollInitiateMintBadge.tsx b/app/components/scroll/ScrollInitiateMintBadge.tsx new file mode 100644 index 0000000000..ddda7a850f --- /dev/null +++ b/app/components/scroll/ScrollInitiateMintBadge.tsx @@ -0,0 +1,150 @@ +import { useEffect, useState } from "react"; +import { useMessage } from "../../hooks/useMessage"; +import { useAttestation } from "../../hooks/useAttestation"; +import { Stamp, VerifiableCredential } from "@gitcoin/passport-types"; +import { scrollCampaignChain, scrollCanvasProfileRegistryAddress } from "../../config/scroll_campaign"; +import { ProviderWithTitle } from "../ScrollCampaign"; +import { ScrollCampaignPage } from "./ScrollCampaignPage"; +import { LoadingBarSection, LoadingBarSectionProps } from "../LoadingBar"; +import { LoadButton } from "../LoadButton"; +import { useWalletStore } from "../../context/walletStore"; +import { ethers } from "ethers"; +import { Hyperlink } from "@gitcoin/passport-platforms"; +import ScrollCanvasProfileRegistryAbi from "../../abi/ScrollCanvasProfileRegistry.json"; + +export const ScrollInitiateMintBadge = ({ + onMint, + credentialsLoading, + hasDeduplicatedCredentials, + deduplicatedBadgeStamps, + highestLevelBadgeStamps, + earnedBadges, +}: { + onMint: (args: { credentials: VerifiableCredential[] }) => Promise; + credentialsLoading: boolean; + hasDeduplicatedCredentials: boolean; + highestLevelBadgeStamps: Stamp[]; + deduplicatedBadgeStamps: Stamp[]; + earnedBadges: ProviderWithTitle[]; +}) => { + const { needToSwitchChain } = useAttestation({ chain: scrollCampaignChain }); + const [hasCanvas, setHasCanvas] = useState(undefined); + const [canvasCheckPaused, setCanvasCheckPaused] = useState(false); + const { failure } = useMessage(); + const address = useWalletStore((state) => state.address); + + const loading = credentialsLoading || hasCanvas === undefined; + + useEffect(() => { + if (!scrollCampaignChain || hasCanvas !== undefined) return; + + (async () => { + try { + // Skip Canvas check if contract address is not provided + if (!scrollCanvasProfileRegistryAddress) { + setHasCanvas(true); + return; + } + + const scrollRpcProvider = new ethers.JsonRpcProvider(scrollCampaignChain.rpcUrl); + const badgeContract = new ethers.Contract( + scrollCanvasProfileRegistryAddress, + ScrollCanvasProfileRegistryAbi.abi, + scrollRpcProvider + ); + + const profileAddress = await badgeContract.getProfile(address); + const hasCanvas = await badgeContract.isProfileMinted(profileAddress); + + setHasCanvas(hasCanvas); + setCanvasCheckPaused(true); + setTimeout(() => setCanvasCheckPaused(false), 10000); + } catch (error) { + console.error("Error checking for canvas profile", error); + failure({ + title: "Error", + message: "An unexpected error occurred while checking for your Scroll Canvas profile.", + }); + } + })(); + }, [address, hasCanvas, failure]); + + const hasBadge = highestLevelBadgeStamps.length > 0; + const hasMultipleBadges = highestLevelBadgeStamps.length > 1; + + const ScrollLoadingBarSection = (props: LoadingBarSectionProps) => ( + + ); + + return ( + + + {hasBadge ? "Congratulations!" : "We're sorry!"} + + + {hasBadge ? ( +
+ You qualify for {highestLevelBadgeStamps.length} badge{hasMultipleBadges ? "s" : ""}. + {hasCanvas ? ( + <> Mint your badge{hasMultipleBadges ? "s" : ""} and get a chance to work with us. + ) : ( + <> +
+
+ It looks like you don't have a Canvas yet. Get yours{" "} + here! + + )} + {hasDeduplicatedCredentials + ? " (Some badge credentials could not be validated because they have already been claimed on another address.)" + : ""} +
+ ) : hasDeduplicatedCredentials ? ( + "Your badge credentials have already been claimed with another address." + ) : ( + "You don't qualify for any badges." + )} +
+ + {hasBadge && ( +
+ {hasCanvas === true ? ( + <> + + onMint({ + credentials: deduplicatedBadgeStamps.map(({ credential }) => credential), + }) + } + isLoading={loading} + className="text-color-1 text-lg font-bold bg-[#FF684B] hover:brightness-150 py-3 transition-all duration-200" + > +
+ Mint Badge{hasMultipleBadges ? "s" : ""} +
+
+ {needToSwitchChain && ( +
+ You will be prompted to switch to the Scroll chain, and then to submit a transaction. +
+ )} + + ) : ( + setHasCanvas(undefined)} + isLoading={hasCanvas === undefined || canvasCheckPaused} + className="text-color-1 text-lg font-bold bg-[#FF684B] hover:brightness-150 py-3 transition-all duration-200" + > + {hasCanvas === undefined ? "Checking..." : "Check Again"} + + )} +
+ )} +
+ ); +}; diff --git a/app/components/scroll/ScrollMintPage.tsx b/app/components/scroll/ScrollMintPage.tsx index 11cc1790cd..2472804fde 100644 --- a/app/components/scroll/ScrollMintPage.tsx +++ b/app/components/scroll/ScrollMintPage.tsx @@ -1,65 +1,31 @@ import { useContext, useEffect, useMemo, useState } from "react"; import { useMessage } from "../../hooks/useMessage"; import { CeramicContext } from "../../context/ceramicContext"; -import { useAttestation } from "../../hooks/useAttestation"; -import { PROVIDER_ID, Passport, Stamp } from "@gitcoin/passport-types"; +import { Passport, Stamp, VerifiableCredential } from "@gitcoin/passport-types"; import { - badgeContractInfo, scrollCampaignBadgeProviderInfo, scrollCampaignBadgeProviders, scrollCampaignChain, } from "../../config/scroll_campaign"; -import { ProviderWithTitle } from "../ScrollCampaign"; -import { ScrollCampaignPage } from "./ScrollCampaignPage"; -import { LoadingBarSection, LoadingBarSectionProps } from "../LoadingBar"; -import { LoadButton } from "../LoadButton"; - -export const getEarnedBadges = (badgeStamps: Stamp[]): ProviderWithTitle[] => { - if (badgeStamps.length === 0) { - return []; - } - return badgeContractInfo.map((contract) => { - const relevantStamps = badgeStamps.filter((stamp) => - contract.providers.some(({ name }) => name === stamp.provider) - ); - - if (relevantStamps.length === 0) { - return { - title: contract.title, - name: "No Provider" as PROVIDER_ID, - image: "", - level: 0, - }; - } - - const highestLevelProvider = relevantStamps.reduce( - (highest, stamp) => { - const provider = contract.providers.find(({ name }) => name === stamp.provider); - if (provider && provider.level > highest.level) { - return provider; - } - return highest; - }, - { level: -1, name: "No Provider" as PROVIDER_ID, image: "" } - ); - - return { - title: contract.title, - ...highestLevelProvider, - }; - }); -}; +import { useWalletStore } from "../../context/walletStore"; +import { ethers } from "ethers"; +import PassportScoreScrollBadgeAbi from "../../abi/PassportScoreScrollBadge.json"; +import { ScrollMintingBadge } from "./ScrollMintingBadge"; +import { ScrollInitiateMintBadge } from "./ScrollInitiateMintBadge"; export const ScrollMintBadge = ({ - onMintBadge, + onMint, + syncingToChain, }: { - onMintBadge: (earnedBadges: ProviderWithTitle[]) => Promise; + onMint: (args: { credentials: VerifiableCredential[] }) => Promise; + syncingToChain: boolean; }) => { - const { failure } = useMessage(); - const { database } = useContext(CeramicContext); - const { needToSwitchChain } = useAttestation({ chain: scrollCampaignChain }); - const [passport, setPassport] = useState(undefined); + const { database } = useContext(CeramicContext); + const { failure } = useMessage(); + const [deduplicatedBadgeStamps, setDeduplicatedBadgeStamps] = useState([]); + const [checkingOnchainBadges, setCheckingOnchainBadges] = useState(true); + const address = useWalletStore((state) => state.address); useEffect(() => { (async () => { @@ -82,15 +48,75 @@ export const ScrollMintBadge = ({ [passport] ); - const loading = !passport; - - const deduplicatedBadgeStamps = useMemo( - // TODO Deduplicate by seeing if in burnedHashes but not user's hashes - () => badgeStamps.filter(({ provider }) => true), - [badgeStamps] - ); - - const hasDeduplicatedCredentials = badgeStamps.length > deduplicatedBadgeStamps.length; + useEffect(() => { + if (!scrollCampaignChain) return; + (async () => { + try { + setCheckingOnchainBadges(true); + + const validBadgeStamps: Stamp[] = []; + + const cachedUserHashes: Record = {}; + const scrollRpcProvider = new ethers.JsonRpcProvider(scrollCampaignChain.rpcUrl); + + await Promise.all( + badgeStamps.map(async (stamp) => { + const stampHash = + "0x" + + Buffer.from((stamp.credential.credentialSubject.hash || "").split(":")[1], "base64").toString("hex"); + + const { contractAddress } = scrollCampaignBadgeProviderInfo[stamp.provider]; + const badgeContract = new ethers.Contract( + contractAddress, + PassportScoreScrollBadgeAbi.abi, + scrollRpcProvider + ); + + if (await badgeContract.burntProviderHashes(stampHash)) { + // If burned, check if it's burned by this user + let index = 0; + let userHash; + do { + if (!cachedUserHashes[contractAddress]) cachedUserHashes[contractAddress] = []; + + if (cachedUserHashes[contractAddress][index] !== undefined) { + // Already pulled from the contract + userHash = cachedUserHashes[contractAddress][index]; + } else { + try { + userHash = await badgeContract.userProviderHashes(address, index); + } catch { + userHash = 0; + } + cachedUserHashes[contractAddress][index] = userHash; + } + + if (userHash === stampHash) { + // If it's burned by this user, it's valid + validBadgeStamps.push(stamp); + } + + index++; + } while (userHash !== 0); + } else { + // If never burned, it's valid + validBadgeStamps.push(stamp); + } + }) + ); + + setDeduplicatedBadgeStamps(validBadgeStamps); + } catch (error) { + console.error("Error checking onchain badges", error); + failure({ + title: "Error", + message: "An unexpected error occurred while checking for existing onchain badges.", + }); + } finally { + setCheckingOnchainBadges(false); + } + })(); + }, [badgeStamps, address, failure]); const highestLevelBadgeStamps = useMemo( () => @@ -109,56 +135,28 @@ export const ScrollMintBadge = ({ [deduplicatedBadgeStamps] ); - const earnedBadges = getEarnedBadges(badgeStamps); + const loading = !passport || checkingOnchainBadges; + const hasDeduplicatedCredentials = !checkingOnchainBadges && badgeStamps.length > deduplicatedBadgeStamps.length; - const hasBadge = deduplicatedBadgeStamps.length > 0; - const hasMultipleBadges = deduplicatedBadgeStamps.length > 1; - - const ScrollLoadingBarSection = (props: LoadingBarSectionProps) => ( - + const earnedBadges = useMemo( + () => + highestLevelBadgeStamps.map(({ provider }) => ({ + ...scrollCampaignBadgeProviderInfo[provider], + name: provider, + })), + [highestLevelBadgeStamps] ); - return ( - - - {hasBadge ? "Congratulations!" : "We're sorry!"} - - - {hasBadge ? ( -
- You qualify for {highestLevelBadgeStamps.length} badge{hasMultipleBadges ? "s" : ""}. Mint your badge - {hasMultipleBadges ? "s" : ""} and get a chance to work with us. - {hasDeduplicatedCredentials - ? " (Some badge credentials could not be validated because they have already been claimed on another address.)" - : ""} -
- ) : hasDeduplicatedCredentials ? ( - "Your badge credentials have already been claimed with another address." - ) : ( - "You don't qualify for any badges." - )} -
- - {hasBadge && ( -
- onMintBadge(earnedBadges)} - isLoading={loading} - className="text-color-1 text-lg font-bold bg-[#FF684B] hover:brightness-150 py-3 transition-all duration-200" - > -
{"Mint Badge"}
-
- {needToSwitchChain && ( -
- You will be prompted to switch to the Scroll chain, and then to submit a transaction. -
- )} -
- )} -
+ return syncingToChain ? ( + + ) : ( + ); }; diff --git a/app/components/scroll/ScrollMintingBadge.tsx b/app/components/scroll/ScrollMintingBadge.tsx index 90d5d8e60f..6c82249378 100644 --- a/app/components/scroll/ScrollMintingBadge.tsx +++ b/app/components/scroll/ScrollMintingBadge.tsx @@ -13,7 +13,7 @@ export const ScrollMintingBadge = ({ earnedBadges }: { earnedBadges: ProviderWit
-
Minting badges...
+
Minting badge{earnedBadges.length > 1 ? "s" : ""}...
diff --git a/app/config/scroll_campaign.ts b/app/config/scroll_campaign.ts index eb0c82eb6d..7894c2daa4 100644 --- a/app/config/scroll_campaign.ts +++ b/app/config/scroll_campaign.ts @@ -50,3 +50,5 @@ export const scrollCampaignChain = chains.find(({ id }) => id === SCROLL_CHAIN_I if (scrollCampaignBadgeProviders.length === 0) { console.error("No NEXT_PUBLIC_SCROLL_BADGE_PROVIDER_INFO has been configured"); } + +export const scrollCanvasProfileRegistryAddress = process.env.NEXT_PUBLIC_SCROLL_CANVAS_PROFILE_REGISTRY_ADDRESS; diff --git a/app/context/scrollCampaignStore.tsx b/app/context/scrollCampaignStore.tsx deleted file mode 100644 index 1ac0522896..0000000000 --- a/app/context/scrollCampaignStore.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { VerifiableCredential } from "@gitcoin/passport-types"; -import { create } from "zustand"; - -/** - * Store & manage the credentials relevant for the scroll campaign - */ -const scrollStampsStore = create<{ - credentials: VerifiableCredential[]; - setCredentials: (credentials: VerifiableCredential[]) => {}; -}>((set) => ({ - credentials: [] as VerifiableCredential[], - setCredentials: async (credentials: VerifiableCredential[]) => { - set({ credentials }); - }, -})); - -// Use as hook -export const useScrollStampsStore = scrollStampsStore; diff --git a/app/hooks/useMintBadge.tsx b/app/hooks/useMintBadge.tsx index bb89a4e18b..c5f38e531e 100644 --- a/app/hooks/useMintBadge.tsx +++ b/app/hooks/useMintBadge.tsx @@ -1,29 +1,24 @@ import { useState } from "react"; import { useAttestation } from "./useAttestation"; -import { useScrollStampsStore } from "../context/scrollCampaignStore"; import { jsonRequest } from "../utils/AttestationProvider"; import { useMessage } from "./useMessage"; import { useNavigateToLastStep } from "./useNextCampaignStep"; import { useWeb3ModalAccount } from "@web3modal/ethers/react"; import { iamUrl } from "../config/stamp_config"; import { scrollCampaignChain } from "../config/scroll_campaign"; -import { EasPayload } from "@gitcoin/passport-types"; -import { ProviderWithTitle } from "../components/ScrollCampaign"; +import { EasPayload, VerifiableCredential } from "@gitcoin/passport-types"; export const useMintBadge = () => { const { getNonce, issueAttestation } = useAttestation({ chain: scrollCampaignChain }); - const { credentials } = useScrollStampsStore(); const { address } = useWeb3ModalAccount(); const { failure } = useMessage(); const goToLastStep = useNavigateToLastStep(); const [syncingToChain, setSyncingToChain] = useState(false); - const [earnedBadges, setEarnedBadges] = useState([]); const [badgesFreshlyMinted, setBadgesFreshlyMinted] = useState(false); - const onMint = async (badges: ProviderWithTitle[]) => { + const onMint = async ({ credentials }: { credentials: VerifiableCredential[] }) => { try { - setEarnedBadges(badges); setSyncingToChain(true); const nonce = await getNonce(); @@ -38,8 +33,8 @@ export const useMintBadge = () => { const url = `${iamUrl}v0.0.0/scroll/dev`; const { data }: { data: EasPayload } = await jsonRequest(url, { recipient: address || "", - credentials: credentials, chainIdHex: scrollCampaignChain?.id, + credentials, nonce, }); @@ -70,7 +65,6 @@ export const useMintBadge = () => { return { onMint, syncingToChain, - earnedBadges, badgesFreshlyMinted, }; }; diff --git a/iam/__tests__/scrollDevBadge.test.ts b/iam/__tests__/scrollDevBadge.test.ts new file mode 100644 index 0000000000..6f091124d8 --- /dev/null +++ b/iam/__tests__/scrollDevBadge.test.ts @@ -0,0 +1,109 @@ +import { Request, Response } from "express"; +import { ethers } from "ethers"; +import { scrollDevBadgeHandler, getScrollRpcUrl } from "../src/utils/scrollDevBadge"; +import { getAttestationSignerForChain } from "../src/utils/attestations"; +import { hasValidIssuer } from "../src/issuers"; +import { getEASFeeAmount } from "../src/utils/easFees"; + +// Mock external dependencies +jest.mock("@spruceid/didkit-wasm-node"); +jest.mock("ethers"); +jest.mock("../src/utils/easFees"); +jest.mock("../src/issuers"); +jest.mock("../src/utils/attestations"); + +describe("scrollDevBadgeHandler", () => { + let mockReq: Partial; + let mockRes: Partial; + let mockJson: jest.Mock; + let mockStatus: jest.Mock; + + beforeEach(() => { + const mockSigner = { + _signTypedData: jest.fn().mockResolvedValue("0xSignature"), + }; + (getAttestationSignerForChain as jest.Mock).mockResolvedValue(mockSigner); + + (hasValidIssuer as jest.Mock).mockReturnValue(true); + + (getEASFeeAmount as jest.Mock).mockReturnValue(1234); + + mockJson = jest.fn(); + mockStatus = jest.fn().mockReturnThis(); + mockRes = { + json: mockJson, + status: mockStatus, + }; + mockReq = { + body: { + credentials: [], + nonce: "123", + chainIdHex: "0x82750", + }, + }; + + // Mock environment variables + process.env.SCROLL_BADGE_PROVIDER_INFO = JSON.stringify({ + "test-provider": { + contractAddress: "0x1234567890123456789012345678901234567890", + level: 1, + }, + }); + process.env.SCROLL_BADGE_ATTESTATION_SCHEMA_UID = "0xSchema"; + process.env.ALCHEMY_API_KEY = "test-api-key"; + + (ethers.Contract as unknown as jest.Mock).mockImplementation(() => ({ + badgeLevel: jest.fn().mockResolvedValue({ toNumber: () => 0 }), + })); + }); + + it("should return an error if no credentials are provided", async () => { + await scrollDevBadgeHandler(mockReq as Request, mockRes as Response); + expect(mockStatus).toHaveBeenCalledWith(400); + expect(mockJson).toHaveBeenCalledWith({ error: "No stamps provided" }); + }); + + it("should return an error if the recipient is invalid", async () => { + mockReq.body.credentials = [{ credentialSubject: { id: "invalid:id" } }]; + await scrollDevBadgeHandler(mockReq as Request, mockRes as Response); + expect(mockStatus).toHaveBeenCalledWith(400); + expect(mockJson).toHaveBeenCalledWith({ error: "Invalid recipient" }); + }); + + it("should process valid credentials and return a signed payload", async () => { + const mockCredential = { + credentialSubject: { + id: "did:pkh:eip155:1:0x1234567890123456789012345678901234567890", + provider: "test-provider", + hash: "v0.0.0:JnHtXuRm2roGRwbYfHtWYSwMma3Oeh3yUl3hmZ3k96U=", + }, + issuer: "did:key:test", + }; + mockReq.body.credentials = [mockCredential]; + + // Mock the necessary functions + jest.spyOn(ethers.utils, "splitSignature").mockReturnValue({ v: 27, r: "0xr", s: "0xs" } as any); + + await scrollDevBadgeHandler(mockReq as Request, mockRes as Response); + + await new Promise((resolve) => setTimeout(resolve, 400)); + + expect(mockJson).toHaveBeenCalled(); + const response = mockJson.mock.calls[0][0]; + expect(response).toHaveProperty("passport"); + expect(response).toHaveProperty("signature"); + expect(response.signature).toEqual({ v: 27, r: "0xr", s: "0xs" }); + }); +}); + +describe("getScrollRpcUrl", () => { + it("should return the correct mainnet URL", () => { + const url = getScrollRpcUrl({ chainIdHex: "0x82750" }); + expect(url).toBe("https://scroll-mainnet.g.alchemy.com/v2/test-api-key"); + }); + + it("should return the correct sepolia URL", () => { + const url = getScrollRpcUrl({ chainIdHex: "0x1234" }); + expect(url).toBe("https://scroll-sepolia.g.alchemy.com/v2/test-api-key"); + }); +}); diff --git a/iam/src/utils/scrollDevBadge.ts b/iam/src/utils/scrollDevBadge.ts index 83d7f2c9d7..534168131d 100644 --- a/iam/src/utils/scrollDevBadge.ts +++ b/iam/src/utils/scrollDevBadge.ts @@ -91,7 +91,7 @@ async function queryBadgeLevel({ } } -export const scrollDevBadgeHandler = (req: Request, res: Response): void => { +export const scrollDevBadgeHandler = (req: Request, res: Response): Promise => { try { const { credentials, nonce, chainIdHex } = req.body as EasRequestBody; if (!Object.keys(onchainInfo).includes(chainIdHex)) {