|_ [bowl:gall desk=tape redirect-str=tape] ++ favicon %+ weld "" "" ++ $ ;html ;head ;meta(charset "utf-8"); ;meta(name "viewport", content "width=device-width, initial-scale=1, shrink-to-fit=no"); ;link(rel "icon", type "image/svg+xml", href (weld "data:image/svg+xml;utf8," favicon)); == ;body ;main#login-page.white ;h1.tc:"Login" ;button(id "mauth"):"Login via 🦊MetaMask »" ;script(type "module"):"{metamask-script}" :: ;script(type "importmap"):"{import-script}" ;div(id "wallet-points"); ;div(id "spinner"); ;h2.tc: Join the Urbit Network ;div.tc.nudge ;a.button/"https://redhorizon.com/join/2d55b768-a5f4-45cf-a4e5-a4302e05a1f9":"Get Urbit ID »" ;p:"If you don't have an Urbit ID, get a fucking $URBIT token." == == == == ++ import-script ^~ %- trip ''' {"imports": { "ethers": "/node_modules/ethers/" }} ''' ++ fetch-urls ^- tape """ const sigilUrl = "/{desk}/sigil/"; const secretUrl= "/{desk}/metamask"; const authUrl= "/{desk}/auth"; const redirectUrl = "{redirect-str}"; """ ++ metamask-script ^~ %+ weld fetch-urls %- trip ''' import { ethers } from "https://cdnjs.cloudflare.com/ajax/libs/ethers/6.7.0/ethers.min.js"; const AZIMUTH_ADDRESS = "0x223c067F8CF28ae173EE5CafEa60cA44C335fecB"; const AZIMUTH_ABI_MINI = [{ "constant": true, "inputs": [{ "name": "_whose", "type": "address" }], "name": "getOwnedPoints", "outputs": [{ "name": "ownedPoints", "type": "uint32[]" }], "payable": false, "stateMutability": "view", "type": "function" }]; const spinner = document.getElementById("spinner"); const pointsDiv = document.getElementById("wallet-points"); const metamaskButton = document.getElementById("mauth"); let ethAddress; window.addEventListener("DOMContentLoaded", () => { metamaskButton.addEventListener("click", (event) => { event.preventDefault(); // Prevent the form from submitting the default way metamaskButton.disabled = true; getProvider().then(provider => { getPoints(provider).then(points => { console.log({points}) points.forEach(point => { insertSigil(point); }) // why doesn't this work wtf // for (const points of points){ // console.log({point}) // } }).catch(e => { metamaskButton.disabled = false; }) }) }); }); async function insertSigil(point){ const div = document.createElement("div"); div.style.cursor = "pointer"; const sigilDiv = await fetchSigil(point); div.innerHTML = sigilDiv; div.addEventListener("click", e => { if (spinner.innerText) return spinner.innerText = "Logging in..." metamaskLogin(ethAddress, point) }) pointsDiv.appendChild(div); } async function fetchSigil(ship) { try { const response = await fetch(sigilUrl + ship); if (response.ok) { const data = await response.text(); return data; } else { throw new Error('Failed to fetch sigil'); } } catch (error) { console.error('Error fetching sigil :', error); } } async function fetchSecret() { try { const response = await fetch(secretUrl); if (response.ok) { const data = await response.json(); return data.challenge; } else { throw new Error('Failed to retrieve secret'); } } catch (error) { console.error('Error fetching secret:', error); } } async function getProvider(){ if (typeof window.ethereum !== 'undefined') { try { const accounts = await window.ethereum.request({ method: "eth_requestAccounts" }); const account = accounts[0]; ethAddress = account; console.log("logged with metamask on account", account); const provider = new ethers.BrowserProvider(window.ethereum) const t1 = await provider.getBalance(account) console.log({t1}) const signer = await provider.getSigner(); console.log({provider, signer}) return signer } catch (error) { alert("MetaMask initialization failed"); } } else { alert("MetaMask is not installed. Please install it to continue."); } } async function metamaskLogin(account, point){ // Fetch the secret from the server const challenge = await fetchSecret(); const signature = await window.ethereum.request({ method: "personal_sign", params: [challenge, account], }); const response = await fetch(authUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ who: Number(point), challenge, address: account, signature: signature }), }); if (response.ok) { // location.reload(); window.location.replace(redirectUrl); } else { alert("Login failed. Please try again."); } } async function getPoints(provider){ const address = provider.address; const contract = new ethers.Contract( AZIMUTH_ADDRESS, AZIMUTH_ABI_MINI, provider, ); const res = await contract.getOwnedPoints(address); return res.toArray(); } ''' --