Search
Search

Transaction: c38ESye...biau

Signed by
Receiver
Status
Succeeded
Transaction Fee
0.00111 
Deposit Value
0 
Gas Used
11 Tgas
Attached Gas
100 Tgas
Created
February 28, 2024 at 8:21:25pm
Hash
c38ESyedqTwUYsoFRqCfLqUZeiAt9fGdHKxVNmcbiau

Actions

Called method: 'set' in contract: social.near
Arguments:
{ "data": { "mattb.near": { "widget": { "NearBadger.Pages.Authentication": { "": "const { accountId, showPlatform, code, state } = props;\n\nconst $ = VM.require(\"sdks.near/widget/Loader\");\nconst { LensSDK } = $(\"@sdks/lens-sdk\");\nconst { EthereumSigner } = $(\"@sdks/eth-signer\");\nconst lens = new LensSDK(State, state);\n\nconst NEARBADGER_VERIFIERS_API = \"https://api.nearbadger.vercel.app\";\nconst VERIFY_PLATFORM_ENDPOINT = \"verify\";\nconst CHALLENGE_ENDPONT = \"challenge\";\nconst LOGO_URL =\n \"https://ipfs.near.social/ipfs/bafkreiagecke7lqgrdbzraafedvei47zshhtptelx5n2j4lldetm5or26q\";\nconst LENS_LOGO_URL =\n \"https://ipfs.near.social/ipfs/bafkreiggkmczb7v43nicdia4n7xqkgynopby5k3nxs3zj6fij5eeurh23i\";\nconst FARCASTER_LOGO_URL =\n \"https://ipfs.near.social/ipfs/bafkreia2gbtoqi6ysk2grk3v3n2qkwgfjogml5icntyp5ykdij6q457lay\";\nconst FARCASTER_BLACK_LOGO_URL =\n \"https://ipfs.near.social/ipfs/bafkreif2ff55fa77acvcclxlccsidhyz5sos3abs5yln7daotbp35nwa7a\";\nconst X_LOGO_URL =\n \"https://ipfs.near.social/ipfs/bafkreighn2xduhiqyf3kqn5nmlmdkekspde7lgk3rpf7xfhigntrgsobsi\";\nconst X_BLACK_LOGO_URL =\n \"https://ipfs.near.social/ipfs/bafkreie3fgyixcxtqccylopewsodmfmci2ub7xwpx6aurimhuzxqytbyka\";\n\nconst REGISTRY_CONTRACT = \"checks.integrations.near\";\nconst TWITTER_AUTH_URL = `https://twitter.com/i/oauth2/authorize?state=twitter.${\n context.accountId + \".\" + Math.floor(Math.random() * 10000000)\n}&code_challenge_method=plain&code_challenge=nearbadger&client_id=MjJLQ1U4aTdJWjgwMTZyb0o3YUg6MTpjaQ&response_type=code&redirect_uri=https%3A%2F%2Fnear.social%2Fmattb.near%2Fwidget%2FNearBadger.Pages.Authentication&scope=users.read%20tweet.read`;\n\nconst [platform, setPlatform] = useState(\"\");\nconst [evmAddress, setEvmAddress] = useState(\"\");\nconst [loadedProfiles, setLoadedProfiles] = useState(false);\nconst [lensProfiles, setLensProfiles] = useState([]);\nconst [selectedHandle, setSelectedHandle] = useState(\"\");\nconst [proof, setProof] = useState(\"\");\nconst [finished, setFinished] = useState(false);\nconst [displayError, setDisplayError] = useState(false);\nconst [success, setSuccess] = useState(false);\nconst cleanSelectedHandle = useMemo(() => {\n let cleanAddress =\n selectedHandle[0] == \"@\"\n ? selectedHandle.substring(1, selectedHandle.length)\n : selectedHandle;\n\n return cleanAddress.split(\".eth\").shift();\n}, [selectedHandle]);\nconst [displayHandle, setDisplayHandle] = useState(\"\");\nconst [loadingEvmAddress, setLoadingEvmAddress] = useState(false);\nconst [onInit, setOnInit] = useState(true);\nconst [twitterUrl, setTwitterUrl] = useState(\"\");\nconst [challenge, setChallenge] = useState(\"\");\nconst [loading, setLoading] = useState(false);\nconst [loadingTwitterChallenge, setLoadingTwitterChallenge] = useState(false);\nconst timeout = null;\n\nif (showPlatform) {\n setPlatform(showPlatform);\n}\n\nif (!evmAddress && Ethers.provider()) {\n if (Ethers.provider().provider?.isMetaMask) {\n const [account] = Ethers.provider().provider._state.accounts;\n setEvmAddress(account);\n } else if (Ethers.provider().provider?.connector) {\n const [account] = Ethers.provider().provider.connector.accounts;\n setEvmAddress(account);\n } else {\n Ethers.provider()\n .send(\"eth_requestAccounts\", [])\n .then(([account]) => {\n setEvmAddress(account);\n });\n }\n}\n\nuseEffect(() => {\n if (!evmAddress) {\n return;\n }\n}, [platform]);\n\nif (evmAddress && platform === \"lens\" && !selectedHandle) {\n lens.authentication\n .profiles({\n for: evmAddress,\n })\n .then((profiles) => {\n if (profiles.length > 0) {\n const handles = profiles.map(\n (profile) => `${profile.handle.fullHandle.split(\"/\").pop()}.lens`\n );\n\n setSelectedHandle(handles[0]);\n setLensProfiles(handles);\n }\n });\n}\n\nconst Main = styled.div`\n width:100%;\n min-height:100vh;\n padding:3rem 0;\n background-color:#fafafa;\n border-radius:20px;\n display:flex;\n justify-content:center;\n align-items:center;\n`;\n\nconst Modal = styled.div`\n display:flex;\n max-width:350px;\n min-width:250px;\n align-items:center;\n justify-content:center;\n flex-direction:column;\n border:1px solid rgba(0,0,0,.1);\n border-radius:20px;\n padding:5rem 2rem;\n margin-top:auto;\n margin-bottom:auto;\n background-color:#fff;\n flex-grow:0;\n flex-shrink:1;\n`;\n\nconst Logo = styled.img`\n max-width:80px;\n margin-bottom:1rem;\n opacity:.8;\n + p {\n margin-bottom:1.5rem;\n font-size:.9rem;\n }\n`;\n\nconst AuthButton = styled.button`\n position:relative;\n padding:.4rem .7rem .4rem 2.7rem;\n border-radius:7px;\n background-color:${({ background }) => `${background || \"#f2f2f2\"}`};\n font-size:.8rem;\n font-weight:bold;\n border:1px solid ${({ border }) => `${border || \"rgba(0,0,0,.05)\"}`};\n color:${({ color }) => `${color || \"#000\"}`};\n min-width:240px;\n text-align:center;\n cursor:pointer;\n box-shadow: 0 0 0 0px rgba(0,0,0,.05);\n transition: all .2s;\n display:block;\n margin:0;\n\n margin-bottom:10px;\n\n :last-of-type {\n margin-bottom:10px;\n }\n\n &[href] {\n text-decoration:none!important;\n :last-of-type {\n margin-bottom:20px;\n }\n }\n\n :hover, :focus {\n box-shadow: 0 0 0 3px rgba(0,0,0,.05);\n transition: all .2s;\n border:1px solid ${({ border }) => `${border || \"rgba(0,0,0,.05)\"}`};\n color:${({ color }) => `${color || \"#000\"}`};\n }\n \n .badge {\n border-radius:0;\n display:flex;\n align-items:center;\n justify-content:center;\n height:100%;\n position:absolute;\n left:0;\n top:0;\n border-right:1px solid ${({ border }) =>\n `${border || \"rgba(0,0,0,.05)\"}`};\n padding:${({ padding }) => `${padding || \"0 7px\"}`};\n min-width:40px;\n\n img {\n display:block;\n position:relative;\n padding:0;\n margin:0;\n left:0;\n width:${({ badgeSize }) => `${badgeSize || \"20px\"}`};\n pointer-events:none;\n }\n }\n`;\n\nconst Disclaimer = styled.p`\n max-width:300px;\n font-size:.7rem;\n text-align:center;\n margin-bottom:7px;\n`;\n\nconst Header = styled.h3`\n display:flex;\n align-items:center;\n justify-content:center;\n font-weight:bold;\n margin-bottom:1.5rem;\n\n img {\n max-width:20px;\n margin-right:5px;\n }\n`;\n\nconst Step = styled.p`\n display:flex;\n align-items:center;\n font-weight:bold;\n`;\n\nconst StepDescription = styled.div`\n margin-bottom:2rem;\n font-size:.8rem;\n\n :last-of-type {\n margin-bottom:2.5rem;\n }\n\n button {\n align-self:center;\n border-radius:50px;\n font-weight:bold;\n color:#000;\n background-color:#F2F2F2;\n border:1px solid rgba(0,0,0,.05);\n padding:.3rem 1rem;\n font-size:.8rem;\n cursor:pointer;\n transition: all .2s;\n text-decoration:none!important;\n margin-right:10px;\n \n :hover {\n box-shadow: 0 0 0 3px rgba(0,0,0,.05);\n border:1px solid rgba(0,0,0,.05);\n transition: all .2s;\n color:#000;\n background-color:#F2F2F2;\n }\n }\n`;\n\nconst FinishButton = styled.a`\n align-self:center;\n border-radius:50px;\n font-weight:bold;\n color:#000;\n background-color:#F2F2F2;\n border:1px solid rgba(0,0,0,.05);\n padding:.8rem 2rem;\n font-size:17px;\n cursor:pointer;\n transition: all .2s;\n text-decoration:none!important;\n margin-bottom:15px;\n min-width:150px;\n display:flex;\n align-items:center;\n justify-content:center;\n\n &.disabled {\n pointer-events:none;\n opacity:.5;\n }\n \n :hover {\n box-shadow: 0 0 0 3px rgba(0,0,0,.05);\n transition: all .2s;\n color:#000;\n }\n`;\n\nconst AuthProcessWrapper = styled.div`\n display:flex;\n flex-direction:column;\n width:100%;\n justify-content:center;\n`;\n\nconst Handle = styled.button`\n align-self:center;\n border-radius:50px;\n font-weight:bold;\n color:#000;\n background-color:#F2F2F2;\n border:1px solid rgba(0,0,0,.05);\n box-shadow: 0 0 0 ${({ selected }) =>\n selected ? \"3px\" : \"0px\"} rgba(0,0,0,.05);\n padding:.3rem 1rem;\n font-size:.8rem;\n cursor:pointer;\n transition: all .2s;\n text-decoration:none!important;\n margin-right:10px;\n\n :hover {\n box-shadow: 0 0 0 3px rgba(0,0,0,.05);\n transition: all .2s;\n color:#000;\n }\n`;\n\nconst ProfileInput = styled.input`\n border:0;\n padding: .5rem;\n border:1px solid rgba(0,0,0,.1);\n border-radius:10px;\n`;\n\nconst ErrorPill = styled.div`\n background-color: #D32F2F;\n border-color: #B71C1C;\n border-style: solid;\n border-width: 1px;\n border-radius: 8px;\n padding: 20px;\n color: white;\n max-width: 300px;\n margin: auto;\n margin-bottom:1rem;\n font-size:.8rem;\n`;\n\nconst Spinner = styled.div`\n @keyframes rotation {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n }\n\n .spinner {\n width: 40px;\n height: 40px;\n border: 5px solid rgba(0,0,0,.1);\n border-bottom-color: rgba(0,0,0,.4);\n border-radius: 50%;\n display: inline-block;\n box-sizing: border-box;\n animation: rotation .5s linear infinite;\n }\n`;\n\nconst ErrorModal = ({ children }) => {\n return (\n <>\n {displayError && (\n <ErrorPill>\n {children.length ? (\n children\n ) : (\n <>\n Looks like there was an error verifying your profile ownership.\n Please, review each step and try again.\n </>\n )}\n </ErrorPill>\n )}\n </>\n );\n};\n\nconst signProof = (platform) => {\n asyncFetch(`${NEARBADGER_VERIFIERS_API}/challenge/${platform}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify({\n accountId: context.accountId,\n handle: cleanSelectedHandle,\n }),\n }).then(({ ok, body: { challenge } }) => {\n if (ok) {\n EthereumSigner.sign(challenge.toString()).then((proof) => {\n setProof(proof);\n });\n } else {\n setDisplayError(true);\n }\n });\n};\n\nconst verifyProof = (platform, registryContract) => {\n setDisplayError(false);\n\n asyncFetch(`${NEARBADGER_VERIFIERS_API}/verify/${platform}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify({\n accountId: context.accountId,\n handle: cleanSelectedHandle || \"\",\n proof,\n challenge: challenge || \"\",\n }),\n }).then(\n ({\n ok,\n body: { expirationBlockHeight, signature, handle: customHandle },\n }) => {\n if (ok) {\n setSuccess(true);\n\n Near.call(\n registryContract || REGISTRY_CONTRACT,\n \"register_social\",\n {\n platform,\n signature,\n handle: customHandle || cleanSelectedHandle,\n proof,\n max_block_height: expirationBlockHeight,\n },\n null,\n 0.01 * Math.pow(10, 24)\n );\n } else {\n setDisplayError(true);\n }\n setLoading(false);\n }\n );\n};\n\nconst disabledAuthButtonStyles = {\n opacity: \".5\",\n pointerEvents: \"none\",\n};\n\nconst storePlatform = (platform) => {\n Storage.set(\n \"platform\",\n JSON.stringify({\n platform: platform,\n expiration: Date.parse(new Date()) + 6 * 100000,\n })\n );\n};\n\nconst checkStoredPlatform = () => {\n if (storedPlatform) {\n const { platform, expiration } = JSON.parse(storedPlatform);\n if (expiration > Date.parse(new Date())) {\n setPlatform(platform);\n Storage.set(\"platform\", null);\n }\n }\n};\n\nconst getTwitterChallenge = () => {\n setLoadingTwitterChallenge(true);\n\n asyncFetch(`${NEARBADGER_VERIFIERS_API}/challenge/${platform}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify({\n accountId: context.accountId,\n handle: cleanSelectedHandle,\n }),\n }).then(({ ok, body: { challenge } }) => {\n if (ok) {\n setTwitterUrl(challenge);\n } else {\n setDisplayError(true);\n }\n\n setLoadingTwitterChallenge(false);\n });\n};\n\nconst storedPlatform = null;\n\nif (onInit) {\n storedPlatform = Storage.get(\"platform\");\n checkStoredPlatform();\n setOnInit(false);\n}\n\nuseEffect(() => {\n checkStoredPlatform();\n}, [storedPlatform]);\n\nuseEffect(() => {\n if (code && state) {\n setLoading(true);\n const [statePlatform] = state.split(\".\");\n setPlatform(statePlatform);\n setProof(code);\n }\n}, []);\n\nuseEffect(() => {\n if (platform === \"twitter\" && proof) {\n verifyProof(\"twitter\", \"staging.integrations.near\");\n }\n}, [platform, challenge, proof]);\n\nconst AuthMethods = () => {\n return (\n <>\n <AuthButton\n style={context.accountId ? {} : disabledAuthButtonStyles}\n onClick={() => {\n setPlatform(\"lens\");\n storePlatform(\"lens\");\n }}\n >\n <span className=\"badge\">\n <img src={LENS_LOGO_URL} width=\"100%\" />\n </span>\n Authenticate on Lens\n </AuthButton>\n <AuthButton\n style={context.accountId ? {} : disabledAuthButtonStyles}\n onClick={() => {\n setPlatform(\"farcaster\");\n storePlatform(\"farcaster\");\n }}\n background=\"#8A63D1\"\n color=\"#FFF\"\n border=\"rgba(0,0,0,.15)\"\n badgeSize=\"17px\"\n >\n <span className=\"badge\">\n <img src={FARCASTER_LOGO_URL} width=\"100%\" />\n </span>\n Authenticate on Farcaster\n </AuthButton>\n <AuthButton\n as=\"a\"\n style={context.accountId ? {} : disabledAuthButtonStyles}\n href={TWITTER_AUTH_URL}\n background=\"#000\"\n color=\"#FFF\"\n border=\"rgba(255,255,255,.15)\"\n badgeSize=\"14px\"\n >\n <span className=\"badge\">\n <img src={X_LOGO_URL} width=\"100%\" />\n </span>\n Authenticate on X\n </AuthButton>\n </>\n );\n};\n\nconst AvailableHandles = ({ handles }) => {\n return (\n <>\n {handles.map((handle) => (\n <Handle\n selected={selectedHandle == handle}\n onClick={() => setSelectedHandle(handle)}\n >\n {handle}\n </Handle>\n ))}\n </>\n );\n};\n\nconst Auth = () => {\n return (\n <>\n {!success && (\n <>\n {!platform && <AuthMethods />}\n {platform && <AuthProcess platform={platform} />}\n\n <Disclaimer>\n Authenticating your profile <b>doesn't grant</b> nearbadger write\n access to your account.\n </Disclaimer>\n <Disclaimer>\n Each issued verification will remain <b>valid for 3 months</b>.\n </Disclaimer>\n </>\n )}\n </>\n );\n};\n\nconst Success = () => (\n <>\n {success && (\n <>\n <div style={{ textAlign: \"center\" }}>\n <Header>Identity successfully verified!</Header>\n <p>You may now get back to the app you were browsing</p>\n </div>\n </>\n )}\n </>\n);\n\nconst updateSelectedHandle = (handle) => {\n setSelectedHandle(handle);\n};\n\nconst AuthProcess = ({ platform }) => {\n const process = {\n lens: (\n <AuthProcessWrapper>\n <Header>\n <img src={LENS_LOGO_URL} width=\"100%\" />\n Lens Protocol\n </Header>\n <Step>1. Connect your Ethereum wallet</Step>\n <StepDescription>\n <Web3Connect\n connectLabel=\"Connect wallet\"\n disconnectLabel=\"Disconnect wallet\"\n />\n </StepDescription>\n <Step>2. Choose a profile</Step>\n <StepDescription>\n {lensProfiles.length > 0 && (\n <AvailableHandles handles={lensProfiles} />\n )}\n {lensProfiles.length == 0 && \"No profiles to show yet.\"}\n </StepDescription>\n <Step>3. Sign a proof</Step>\n <StepDescription>\n <button onClick={() => signProof(\"lens\")}>Sign proof</button>\n </StepDescription>\n <ErrorModal />\n <FinishButton onClick={() => verifyProof(\"lens\")}>\n Verify profile\n </FinishButton>\n </AuthProcessWrapper>\n ),\n farcaster: (\n <AuthProcessWrapper>\n <Header>\n <img src={FARCASTER_BLACK_LOGO_URL} width=\"100%\" />\n Farcaster\n </Header>\n <Step>1. Link your Ethereum address to your Farcaster profile</Step>\n <StepDescription>\n To do so, go to the Warpcast app and click{\" \"}\n <b>\n Settings {\">\"} Connected addresses {\">\"} Connect address\n </b>\n <br />\n <br />\n If you already did it, you can skip this step\n </StepDescription>\n <Step>2. Connect your Ethereum wallet</Step>\n <StepDescription>\n <Web3Connect\n connectLabel=\"Connect wallet\"\n disconnectLabel=\"Disconnect wallet\"\n />\n </StepDescription>\n <Step>3. Write down your Farcaster handle</Step>\n <StepDescription>\n <ProfileInput\n placeholder=\"@handle\"\n onChange={({ target: { value: text } }) => {\n if (timeout) {\n clearTimeout(timeout);\n }\n\n timeout = setTimeout(() => {\n setSelectedHandle(text);\n }, 300);\n }}\n />\n </StepDescription>\n <Step>4. Sign a proof</Step>\n <StepDescription>\n <button onClick={() => signProof(\"farcaster\")}>Sign proof</button>\n </StepDescription>\n <ErrorModal />\n <FinishButton onClick={() => verifyProof(\"farcaster\")}>\n Verify profile\n </FinishButton>\n </AuthProcessWrapper>\n ),\n twitter: (\n <AuthProcessWrapper>\n <Header>\n <img src={X_BLACK_LOGO_URL} width=\"100%\" />\n </Header>\n <Step>Something went wrong...</Step>\n <StepDescription>\n Ouch! It looks like we weren't able to verify your information this\n time. But don't worry, you can try it again.\n <br />\n <br />\n <br />\n <FinishButton as=\"a\" href={TWITTER_AUTH_URL}>\n Try again\n </FinishButton>\n </StepDescription>\n </AuthProcessWrapper>\n ),\n };\n\n return process[platform] || <>Auth method not found</>;\n};\n\nconst RequireNearAccount = () => {\n return (\n <>\n {!success && (\n <p style={{ textAlign: \"center\" }}>\n {context.accountId == null ? (\n <>Connect your NEAR account to start the verification process</>\n ) : (\n <>\n This app requires <b>{accountId || context.accountId || \"you\"}</b>{\" \"}\n to verify a profile\n </>\n )}\n </p>\n )}\n </>\n );\n};\n\nreturn (\n <Main>\n <Modal>\n <Logo src={LOGO_URL}></Logo>\n {!loading && (\n <>\n <RequireNearAccount />\n <Auth />\n <Success />\n </>\n )}\n {loading && (\n <>\n <Spinner>\n <span className=\"spinner\"></span>\n </Spinner>\n <p>Verifying proof...</p>\n </>\n )}\n </Modal>\n </Main>\n);\n" } } } } }

Transaction Execution Plan

Convert Transaction To Receipt
Gas Burned:
2 Tgas
Tokens Burned:
0.00025 
Receipt:
Predecessor ID:
Receiver ID:
Gas Burned:
8 Tgas
Tokens Burned:
0.00086 
Called method: 'set' in contract: social.near
Arguments:
{ "data": { "mattb.near": { "widget": { "NearBadger.Pages.Authentication": { "": "const { accountId, showPlatform, code, state } = props;\n\nconst $ = VM.require(\"sdks.near/widget/Loader\");\nconst { LensSDK } = $(\"@sdks/lens-sdk\");\nconst { EthereumSigner } = $(\"@sdks/eth-signer\");\nconst lens = new LensSDK(State, state);\n\nconst NEARBADGER_VERIFIERS_API = \"https://api.nearbadger.vercel.app\";\nconst VERIFY_PLATFORM_ENDPOINT = \"verify\";\nconst CHALLENGE_ENDPONT = \"challenge\";\nconst LOGO_URL =\n \"https://ipfs.near.social/ipfs/bafkreiagecke7lqgrdbzraafedvei47zshhtptelx5n2j4lldetm5or26q\";\nconst LENS_LOGO_URL =\n \"https://ipfs.near.social/ipfs/bafkreiggkmczb7v43nicdia4n7xqkgynopby5k3nxs3zj6fij5eeurh23i\";\nconst FARCASTER_LOGO_URL =\n \"https://ipfs.near.social/ipfs/bafkreia2gbtoqi6ysk2grk3v3n2qkwgfjogml5icntyp5ykdij6q457lay\";\nconst FARCASTER_BLACK_LOGO_URL =\n \"https://ipfs.near.social/ipfs/bafkreif2ff55fa77acvcclxlccsidhyz5sos3abs5yln7daotbp35nwa7a\";\nconst X_LOGO_URL =\n \"https://ipfs.near.social/ipfs/bafkreighn2xduhiqyf3kqn5nmlmdkekspde7lgk3rpf7xfhigntrgsobsi\";\nconst X_BLACK_LOGO_URL =\n \"https://ipfs.near.social/ipfs/bafkreie3fgyixcxtqccylopewsodmfmci2ub7xwpx6aurimhuzxqytbyka\";\n\nconst REGISTRY_CONTRACT = \"checks.integrations.near\";\nconst TWITTER_AUTH_URL = `https://twitter.com/i/oauth2/authorize?state=twitter.${\n context.accountId + \".\" + Math.floor(Math.random() * 10000000)\n}&code_challenge_method=plain&code_challenge=nearbadger&client_id=MjJLQ1U4aTdJWjgwMTZyb0o3YUg6MTpjaQ&response_type=code&redirect_uri=https%3A%2F%2Fnear.social%2Fmattb.near%2Fwidget%2FNearBadger.Pages.Authentication&scope=users.read%20tweet.read`;\n\nconst [platform, setPlatform] = useState(\"\");\nconst [evmAddress, setEvmAddress] = useState(\"\");\nconst [loadedProfiles, setLoadedProfiles] = useState(false);\nconst [lensProfiles, setLensProfiles] = useState([]);\nconst [selectedHandle, setSelectedHandle] = useState(\"\");\nconst [proof, setProof] = useState(\"\");\nconst [finished, setFinished] = useState(false);\nconst [displayError, setDisplayError] = useState(false);\nconst [success, setSuccess] = useState(false);\nconst cleanSelectedHandle = useMemo(() => {\n let cleanAddress =\n selectedHandle[0] == \"@\"\n ? selectedHandle.substring(1, selectedHandle.length)\n : selectedHandle;\n\n return cleanAddress.split(\".eth\").shift();\n}, [selectedHandle]);\nconst [displayHandle, setDisplayHandle] = useState(\"\");\nconst [loadingEvmAddress, setLoadingEvmAddress] = useState(false);\nconst [onInit, setOnInit] = useState(true);\nconst [twitterUrl, setTwitterUrl] = useState(\"\");\nconst [challenge, setChallenge] = useState(\"\");\nconst [loading, setLoading] = useState(false);\nconst [loadingTwitterChallenge, setLoadingTwitterChallenge] = useState(false);\nconst timeout = null;\n\nif (showPlatform) {\n setPlatform(showPlatform);\n}\n\nif (!evmAddress && Ethers.provider()) {\n if (Ethers.provider().provider?.isMetaMask) {\n const [account] = Ethers.provider().provider._state.accounts;\n setEvmAddress(account);\n } else if (Ethers.provider().provider?.connector) {\n const [account] = Ethers.provider().provider.connector.accounts;\n setEvmAddress(account);\n } else {\n Ethers.provider()\n .send(\"eth_requestAccounts\", [])\n .then(([account]) => {\n setEvmAddress(account);\n });\n }\n}\n\nuseEffect(() => {\n if (!evmAddress) {\n return;\n }\n}, [platform]);\n\nif (evmAddress && platform === \"lens\" && !selectedHandle) {\n lens.authentication\n .profiles({\n for: evmAddress,\n })\n .then((profiles) => {\n if (profiles.length > 0) {\n const handles = profiles.map(\n (profile) => `${profile.handle.fullHandle.split(\"/\").pop()}.lens`\n );\n\n setSelectedHandle(handles[0]);\n setLensProfiles(handles);\n }\n });\n}\n\nconst Main = styled.div`\n width:100%;\n min-height:100vh;\n padding:3rem 0;\n background-color:#fafafa;\n border-radius:20px;\n display:flex;\n justify-content:center;\n align-items:center;\n`;\n\nconst Modal = styled.div`\n display:flex;\n max-width:350px;\n min-width:250px;\n align-items:center;\n justify-content:center;\n flex-direction:column;\n border:1px solid rgba(0,0,0,.1);\n border-radius:20px;\n padding:5rem 2rem;\n margin-top:auto;\n margin-bottom:auto;\n background-color:#fff;\n flex-grow:0;\n flex-shrink:1;\n`;\n\nconst Logo = styled.img`\n max-width:80px;\n margin-bottom:1rem;\n opacity:.8;\n + p {\n margin-bottom:1.5rem;\n font-size:.9rem;\n }\n`;\n\nconst AuthButton = styled.button`\n position:relative;\n padding:.4rem .7rem .4rem 2.7rem;\n border-radius:7px;\n background-color:${({ background }) => `${background || \"#f2f2f2\"}`};\n font-size:.8rem;\n font-weight:bold;\n border:1px solid ${({ border }) => `${border || \"rgba(0,0,0,.05)\"}`};\n color:${({ color }) => `${color || \"#000\"}`};\n min-width:240px;\n text-align:center;\n cursor:pointer;\n box-shadow: 0 0 0 0px rgba(0,0,0,.05);\n transition: all .2s;\n display:block;\n margin:0;\n\n margin-bottom:10px;\n\n :last-of-type {\n margin-bottom:10px;\n }\n\n &[href] {\n text-decoration:none!important;\n :last-of-type {\n margin-bottom:20px;\n }\n }\n\n :hover, :focus {\n box-shadow: 0 0 0 3px rgba(0,0,0,.05);\n transition: all .2s;\n border:1px solid ${({ border }) => `${border || \"rgba(0,0,0,.05)\"}`};\n color:${({ color }) => `${color || \"#000\"}`};\n }\n \n .badge {\n border-radius:0;\n display:flex;\n align-items:center;\n justify-content:center;\n height:100%;\n position:absolute;\n left:0;\n top:0;\n border-right:1px solid ${({ border }) =>\n `${border || \"rgba(0,0,0,.05)\"}`};\n padding:${({ padding }) => `${padding || \"0 7px\"}`};\n min-width:40px;\n\n img {\n display:block;\n position:relative;\n padding:0;\n margin:0;\n left:0;\n width:${({ badgeSize }) => `${badgeSize || \"20px\"}`};\n pointer-events:none;\n }\n }\n`;\n\nconst Disclaimer = styled.p`\n max-width:300px;\n font-size:.7rem;\n text-align:center;\n margin-bottom:7px;\n`;\n\nconst Header = styled.h3`\n display:flex;\n align-items:center;\n justify-content:center;\n font-weight:bold;\n margin-bottom:1.5rem;\n\n img {\n max-width:20px;\n margin-right:5px;\n }\n`;\n\nconst Step = styled.p`\n display:flex;\n align-items:center;\n font-weight:bold;\n`;\n\nconst StepDescription = styled.div`\n margin-bottom:2rem;\n font-size:.8rem;\n\n :last-of-type {\n margin-bottom:2.5rem;\n }\n\n button {\n align-self:center;\n border-radius:50px;\n font-weight:bold;\n color:#000;\n background-color:#F2F2F2;\n border:1px solid rgba(0,0,0,.05);\n padding:.3rem 1rem;\n font-size:.8rem;\n cursor:pointer;\n transition: all .2s;\n text-decoration:none!important;\n margin-right:10px;\n \n :hover {\n box-shadow: 0 0 0 3px rgba(0,0,0,.05);\n border:1px solid rgba(0,0,0,.05);\n transition: all .2s;\n color:#000;\n background-color:#F2F2F2;\n }\n }\n`;\n\nconst FinishButton = styled.a`\n align-self:center;\n border-radius:50px;\n font-weight:bold;\n color:#000;\n background-color:#F2F2F2;\n border:1px solid rgba(0,0,0,.05);\n padding:.8rem 2rem;\n font-size:17px;\n cursor:pointer;\n transition: all .2s;\n text-decoration:none!important;\n margin-bottom:15px;\n min-width:150px;\n display:flex;\n align-items:center;\n justify-content:center;\n\n &.disabled {\n pointer-events:none;\n opacity:.5;\n }\n \n :hover {\n box-shadow: 0 0 0 3px rgba(0,0,0,.05);\n transition: all .2s;\n color:#000;\n }\n`;\n\nconst AuthProcessWrapper = styled.div`\n display:flex;\n flex-direction:column;\n width:100%;\n justify-content:center;\n`;\n\nconst Handle = styled.button`\n align-self:center;\n border-radius:50px;\n font-weight:bold;\n color:#000;\n background-color:#F2F2F2;\n border:1px solid rgba(0,0,0,.05);\n box-shadow: 0 0 0 ${({ selected }) =>\n selected ? \"3px\" : \"0px\"} rgba(0,0,0,.05);\n padding:.3rem 1rem;\n font-size:.8rem;\n cursor:pointer;\n transition: all .2s;\n text-decoration:none!important;\n margin-right:10px;\n\n :hover {\n box-shadow: 0 0 0 3px rgba(0,0,0,.05);\n transition: all .2s;\n color:#000;\n }\n`;\n\nconst ProfileInput = styled.input`\n border:0;\n padding: .5rem;\n border:1px solid rgba(0,0,0,.1);\n border-radius:10px;\n`;\n\nconst ErrorPill = styled.div`\n background-color: #D32F2F;\n border-color: #B71C1C;\n border-style: solid;\n border-width: 1px;\n border-radius: 8px;\n padding: 20px;\n color: white;\n max-width: 300px;\n margin: auto;\n margin-bottom:1rem;\n font-size:.8rem;\n`;\n\nconst Spinner = styled.div`\n @keyframes rotation {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n }\n\n .spinner {\n width: 40px;\n height: 40px;\n border: 5px solid rgba(0,0,0,.1);\n border-bottom-color: rgba(0,0,0,.4);\n border-radius: 50%;\n display: inline-block;\n box-sizing: border-box;\n animation: rotation .5s linear infinite;\n }\n`;\n\nconst ErrorModal = ({ children }) => {\n return (\n <>\n {displayError && (\n <ErrorPill>\n {children.length ? (\n children\n ) : (\n <>\n Looks like there was an error verifying your profile ownership.\n Please, review each step and try again.\n </>\n )}\n </ErrorPill>\n )}\n </>\n );\n};\n\nconst signProof = (platform) => {\n asyncFetch(`${NEARBADGER_VERIFIERS_API}/challenge/${platform}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify({\n accountId: context.accountId,\n handle: cleanSelectedHandle,\n }),\n }).then(({ ok, body: { challenge } }) => {\n if (ok) {\n EthereumSigner.sign(challenge.toString()).then((proof) => {\n setProof(proof);\n });\n } else {\n setDisplayError(true);\n }\n });\n};\n\nconst verifyProof = (platform, registryContract) => {\n setDisplayError(false);\n\n asyncFetch(`${NEARBADGER_VERIFIERS_API}/verify/${platform}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify({\n accountId: context.accountId,\n handle: cleanSelectedHandle || \"\",\n proof,\n challenge: challenge || \"\",\n }),\n }).then(\n ({\n ok,\n body: { expirationBlockHeight, signature, handle: customHandle },\n }) => {\n if (ok) {\n setSuccess(true);\n\n Near.call(\n registryContract || REGISTRY_CONTRACT,\n \"register_social\",\n {\n platform,\n signature,\n handle: customHandle || cleanSelectedHandle,\n proof,\n max_block_height: expirationBlockHeight,\n },\n null,\n 0.01 * Math.pow(10, 24)\n );\n } else {\n setDisplayError(true);\n }\n setLoading(false);\n }\n );\n};\n\nconst disabledAuthButtonStyles = {\n opacity: \".5\",\n pointerEvents: \"none\",\n};\n\nconst storePlatform = (platform) => {\n Storage.set(\n \"platform\",\n JSON.stringify({\n platform: platform,\n expiration: Date.parse(new Date()) + 6 * 100000,\n })\n );\n};\n\nconst checkStoredPlatform = () => {\n if (storedPlatform) {\n const { platform, expiration } = JSON.parse(storedPlatform);\n if (expiration > Date.parse(new Date())) {\n setPlatform(platform);\n Storage.set(\"platform\", null);\n }\n }\n};\n\nconst getTwitterChallenge = () => {\n setLoadingTwitterChallenge(true);\n\n asyncFetch(`${NEARBADGER_VERIFIERS_API}/challenge/${platform}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify({\n accountId: context.accountId,\n handle: cleanSelectedHandle,\n }),\n }).then(({ ok, body: { challenge } }) => {\n if (ok) {\n setTwitterUrl(challenge);\n } else {\n setDisplayError(true);\n }\n\n setLoadingTwitterChallenge(false);\n });\n};\n\nconst storedPlatform = null;\n\nif (onInit) {\n storedPlatform = Storage.get(\"platform\");\n checkStoredPlatform();\n setOnInit(false);\n}\n\nuseEffect(() => {\n checkStoredPlatform();\n}, [storedPlatform]);\n\nuseEffect(() => {\n if (code && state) {\n setLoading(true);\n const [statePlatform] = state.split(\".\");\n setPlatform(statePlatform);\n setProof(code);\n }\n}, []);\n\nuseEffect(() => {\n if (platform === \"twitter\" && proof) {\n verifyProof(\"twitter\", \"staging.integrations.near\");\n }\n}, [platform, challenge, proof]);\n\nconst AuthMethods = () => {\n return (\n <>\n <AuthButton\n style={context.accountId ? {} : disabledAuthButtonStyles}\n onClick={() => {\n setPlatform(\"lens\");\n storePlatform(\"lens\");\n }}\n >\n <span className=\"badge\">\n <img src={LENS_LOGO_URL} width=\"100%\" />\n </span>\n Authenticate on Lens\n </AuthButton>\n <AuthButton\n style={context.accountId ? {} : disabledAuthButtonStyles}\n onClick={() => {\n setPlatform(\"farcaster\");\n storePlatform(\"farcaster\");\n }}\n background=\"#8A63D1\"\n color=\"#FFF\"\n border=\"rgba(0,0,0,.15)\"\n badgeSize=\"17px\"\n >\n <span className=\"badge\">\n <img src={FARCASTER_LOGO_URL} width=\"100%\" />\n </span>\n Authenticate on Farcaster\n </AuthButton>\n <AuthButton\n as=\"a\"\n style={context.accountId ? {} : disabledAuthButtonStyles}\n href={TWITTER_AUTH_URL}\n background=\"#000\"\n color=\"#FFF\"\n border=\"rgba(255,255,255,.15)\"\n badgeSize=\"14px\"\n >\n <span className=\"badge\">\n <img src={X_LOGO_URL} width=\"100%\" />\n </span>\n Authenticate on X\n </AuthButton>\n </>\n );\n};\n\nconst AvailableHandles = ({ handles }) => {\n return (\n <>\n {handles.map((handle) => (\n <Handle\n selected={selectedHandle == handle}\n onClick={() => setSelectedHandle(handle)}\n >\n {handle}\n </Handle>\n ))}\n </>\n );\n};\n\nconst Auth = () => {\n return (\n <>\n {!success && (\n <>\n {!platform && <AuthMethods />}\n {platform && <AuthProcess platform={platform} />}\n\n <Disclaimer>\n Authenticating your profile <b>doesn't grant</b> nearbadger write\n access to your account.\n </Disclaimer>\n <Disclaimer>\n Each issued verification will remain <b>valid for 3 months</b>.\n </Disclaimer>\n </>\n )}\n </>\n );\n};\n\nconst Success = () => (\n <>\n {success && (\n <>\n <div style={{ textAlign: \"center\" }}>\n <Header>Identity successfully verified!</Header>\n <p>You may now get back to the app you were browsing</p>\n </div>\n </>\n )}\n </>\n);\n\nconst updateSelectedHandle = (handle) => {\n setSelectedHandle(handle);\n};\n\nconst AuthProcess = ({ platform }) => {\n const process = {\n lens: (\n <AuthProcessWrapper>\n <Header>\n <img src={LENS_LOGO_URL} width=\"100%\" />\n Lens Protocol\n </Header>\n <Step>1. Connect your Ethereum wallet</Step>\n <StepDescription>\n <Web3Connect\n connectLabel=\"Connect wallet\"\n disconnectLabel=\"Disconnect wallet\"\n />\n </StepDescription>\n <Step>2. Choose a profile</Step>\n <StepDescription>\n {lensProfiles.length > 0 && (\n <AvailableHandles handles={lensProfiles} />\n )}\n {lensProfiles.length == 0 && \"No profiles to show yet.\"}\n </StepDescription>\n <Step>3. Sign a proof</Step>\n <StepDescription>\n <button onClick={() => signProof(\"lens\")}>Sign proof</button>\n </StepDescription>\n <ErrorModal />\n <FinishButton onClick={() => verifyProof(\"lens\")}>\n Verify profile\n </FinishButton>\n </AuthProcessWrapper>\n ),\n farcaster: (\n <AuthProcessWrapper>\n <Header>\n <img src={FARCASTER_BLACK_LOGO_URL} width=\"100%\" />\n Farcaster\n </Header>\n <Step>1. Link your Ethereum address to your Farcaster profile</Step>\n <StepDescription>\n To do so, go to the Warpcast app and click{\" \"}\n <b>\n Settings {\">\"} Connected addresses {\">\"} Connect address\n </b>\n <br />\n <br />\n If you already did it, you can skip this step\n </StepDescription>\n <Step>2. Connect your Ethereum wallet</Step>\n <StepDescription>\n <Web3Connect\n connectLabel=\"Connect wallet\"\n disconnectLabel=\"Disconnect wallet\"\n />\n </StepDescription>\n <Step>3. Write down your Farcaster handle</Step>\n <StepDescription>\n <ProfileInput\n placeholder=\"@handle\"\n onChange={({ target: { value: text } }) => {\n if (timeout) {\n clearTimeout(timeout);\n }\n\n timeout = setTimeout(() => {\n setSelectedHandle(text);\n }, 300);\n }}\n />\n </StepDescription>\n <Step>4. Sign a proof</Step>\n <StepDescription>\n <button onClick={() => signProof(\"farcaster\")}>Sign proof</button>\n </StepDescription>\n <ErrorModal />\n <FinishButton onClick={() => verifyProof(\"farcaster\")}>\n Verify profile\n </FinishButton>\n </AuthProcessWrapper>\n ),\n twitter: (\n <AuthProcessWrapper>\n <Header>\n <img src={X_BLACK_LOGO_URL} width=\"100%\" />\n </Header>\n <Step>Something went wrong...</Step>\n <StepDescription>\n Ouch! It looks like we weren't able to verify your information this\n time. But don't worry, you can try it again.\n <br />\n <br />\n <br />\n <FinishButton as=\"a\" href={TWITTER_AUTH_URL}>\n Try again\n </FinishButton>\n </StepDescription>\n </AuthProcessWrapper>\n ),\n };\n\n return process[platform] || <>Auth method not found</>;\n};\n\nconst RequireNearAccount = () => {\n return (\n <>\n {!success && (\n <p style={{ textAlign: \"center\" }}>\n {context.accountId == null ? (\n <>Connect your NEAR account to start the verification process</>\n ) : (\n <>\n This app requires <b>{accountId || context.accountId || \"you\"}</b>{\" \"}\n to verify a profile\n </>\n )}\n </p>\n )}\n </>\n );\n};\n\nreturn (\n <Main>\n <Modal>\n <Logo src={LOGO_URL}></Logo>\n {!loading && (\n <>\n <RequireNearAccount />\n <Auth />\n <Success />\n </>\n )}\n {loading && (\n <>\n <Spinner>\n <span className=\"spinner\"></span>\n </Spinner>\n <p>Verifying proof...</p>\n </>\n )}\n </Modal>\n </Main>\n);\n" } } } } }
Result:
{ "block_height": "113772409" }
No logs
Receipt:
Predecessor ID:
Receiver ID:
Gas Burned:
223 Ggas
Tokens Burned:
0 
Transferred 0.0182  to mattb.near
Empty result
No logs