> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rhinestone.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Relay a transaction

> Authorize and track a same-chain transaction with an embedded wallet or custom signer.

export const CSS = ".rhinestone-1auth-demo .demo-mint-banner {\n  background-color: light-dark(#fef3c7, #422006);\n  border-color: light-dark(#fde68a, #713f12);\n}\n.rhinestone-1auth-demo .oa-demo {\n  margin: 1.5rem 0;\n  border: 1px solid #202127;\n  border-radius: 16px;\n  background: #0b0c0e;\n  overflow: hidden;\n}\n.rhinestone-1auth-demo .oa-demo-head {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 0.75rem;\n  min-height: 39px;\n  padding: 0.625rem 1rem;\n  border-bottom: 1px solid #191a1e;\n}\n.rhinestone-1auth-demo .oa-demo-title {\n  font-size: 0.8125rem;\n  font-weight: 500;\n  letter-spacing: -0.01em;\n  color: #e4e4e9;\n}\n.rhinestone-1auth-demo .oa-demo-status {\n  display: flex;\n  align-items: center;\n  gap: 0.4375rem;\n  flex: 0 0 auto;\n  font-size: 0.75rem;\n  color: #5e5e68;\n}\n.rhinestone-1auth-demo .oa-demo-dot {\n  width: 6px;\n  height: 6px;\n  border-radius: 999px;\n  background: #3f3f48;\n}\n.rhinestone-1auth-demo .oa-demo-dot[data-state=\"on\"] {\n  background: #22c55e;\n  box-shadow: 0 0 8px rgba(34, 197, 94, 0.5);\n}\n.rhinestone-1auth-demo .oa-demo-body {\n  display: flex;\n  flex-direction: column;\n  gap: 0.75rem;\n  padding: 1rem;\n}\n.rhinestone-1auth-demo .demo-container {\n  display: contents;\n}\n.rhinestone-1auth-demo .oa-demo-body > * > [style] {\n  margin: 0 !important;\n}\n.rhinestone-1auth-demo .oa-demo-body > * > div[style]:not([class]) {\n  padding: 0 !important;\n}\n.rhinestone-1auth-demo .oa-demo-body [style] {\n  text-align: left !important;\n}\n.rhinestone-1auth-demo .oa-demo-body [style*=\"justify-content: center\"] {\n  justify-content: flex-start !important;\n}\n.rhinestone-1auth-demo .demo-button {\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  gap: 0.375rem;\n  height: 2.25rem;\n  padding: 0 0.875rem;\n  border: none;\n  border-radius: 10px;\n  background: #4f41ef;\n  color: #ffffff;\n  font-size: 0.875rem;\n  font-weight: 500;\n  cursor: pointer;\n  transition:\n    background 0.15s ease,\n    opacity 0.15s ease;\n}\n.rhinestone-1auth-demo .demo-button:hover:not(:disabled) {\n  background: #6355f5;\n}\n.rhinestone-1auth-demo .demo-button:disabled {\n  opacity: 0.6;\n  cursor: default;\n}\n.rhinestone-1auth-demo .demo-button-secondary {\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  height: 2.25rem;\n  padding: 0 0.875rem;\n  border: 1px solid #2e2e36;\n  border-radius: 10px;\n  background: transparent;\n  color: #c8c8d0;\n  font-size: 0.875rem;\n  font-weight: 500;\n  cursor: pointer;\n  transition:\n    border-color 0.15s ease,\n    color 0.15s ease;\n}\n.rhinestone-1auth-demo .demo-button-secondary:hover:not(:disabled) {\n  border-color: #45454f;\n  color: #f2f2f5;\n}\n.rhinestone-1auth-demo .oa-demo-body > * > .demo-button, .rhinestone-1auth-demo .oa-demo-body > * > .demo-button-secondary {\n  align-self: flex-start;\n}\n.rhinestone-1auth-demo .oa-demo-body input[type=\"checkbox\"] {\n  accent-color: #4f41ef;\n}\n.rhinestone-1auth-demo .demo-result {\n  padding: 0.75rem 0.875rem;\n  border-radius: 10px;\n  background: #14151a;\n}\n.rhinestone-1auth-demo .demo-result-label {\n  font-size: 0.6875rem;\n  font-weight: 500;\n  letter-spacing: 0.08em;\n  text-transform: uppercase;\n  color: #6e6e78;\n}\n.rhinestone-1auth-demo .demo-result-value {\n  margin-top: 0.1875rem;\n  font-family: paperMono, ui-monospace, SFMono-Regular, Menlo, monospace;\n  font-size: 0.8125rem;\n  line-height: 1.5;\n  color: #e4e4e9;\n  overflow-wrap: anywhere;\n}\n.rhinestone-1auth-demo .demo-result-success .demo-result-label {\n  color: #4ade80;\n}\n.rhinestone-1auth-demo .demo-result-error .demo-result-label {\n  color: #f87171;\n}\n.rhinestone-1auth-demo .demo-result-error .demo-result-value {\n  color: #fca5a5;\n}\n.rhinestone-1auth-demo .demo-error {\n  margin: 0;\n  font-size: 0.8125rem;\n  color: #f87171;\n  overflow-wrap: anywhere;\n}\n.rhinestone-1auth-demo .oa-demo-skeleton {\n  display: block;\n  width: 7rem;\n  height: 2.25rem;\n  border-radius: 10px;\n  background: #16171c;\n  animation: rhinestone-1auth-demo-pulse 1.6s ease-in-out infinite;\n}\n@keyframes rhinestone-1auth-demo-pulse {\n  50% {\n    opacity: 0.45;\n  }\n}";

export const SOURCE_COMMIT = "e06ebe8add704e95f679eaddc38fd7ea88cb3de8";

export const SDK_VERSION = "0.10.1";

export const VIEM_VERSION = "2.55.0";

export const STORAGE_KEY = "rhinestone-docs-1auth-account";

export const PROD_BACKENDS = {
  auth: "https://passkey.1auth.app",
  sponsorship: "https://docs.1auth.app/api/sponsorship"
};

export const DEV_BACKENDS = {
  auth: "https://passkey.passkey-test.app",
  sponsorship: "https://docs.passkey-test.app/api/sponsorship"
};

export const PROD_DOCS_HOST = "docs.rhinestone.dev";

export const backends = () => {
  const host = typeof window === "undefined" ? "" : window.location.hostname;
  return host === PROD_DOCS_HOST ? PROD_BACKENDS : DEV_BACKENDS;
};

export const BACKEND_NOTE = "Only the production docs host talks to the production Rhinestone deployment. " + "Every other host — a Mintlify preview, a tunnel, localhost — uses dev, so " + "an unrecognised preview pattern fails towards dev rather than creating " + "passkey state against production.";

export const CDN = spec => "https://esm.sh/" + spec + (spec.startsWith("@rhinestone/1auth@") ? "?deps=viem@" + VIEM_VERSION + "&external=react" : "");

export const shareReact = () => {
  if (window.__OA_SHARED_REACT__) return;
  if (typeof HTMLScriptElement.supports !== "function" || !HTMLScriptElement.supports("importmap")) {
    throw new Error("This demo requires a browser with import-map support.");
  }
  window.__OA_REACT__ = React;
  const reserved = ["default", "import", "export", "class", "function", "const", "let", "var", "new", "delete", "typeof", "void", "in", "of", "do", "if", "else", "for", "while", "switch", "case", "break", "continue", "return", "this", "super", "throw", "try", "catch", "finally", "yield", "await", "enum", "null", "true", "false", "with", "debugger", "instanceof", "extends", "static"];
  const names = Object.keys(React).filter(name => (/^[A-Za-z_$][A-Za-z0-9_$]*$/).test(name) && !reserved.includes(name));
  const source = ["const R = globalThis.__OA_REACT__; export default R;", ...names.map(name => "export const " + name + " = R." + name + ";")].join(" ");
  const jsx = ["const R = globalThis.__OA_REACT__; export const Fragment = R.Fragment;", "export const jsx = (type, props, key) => R.createElement(type, key == null ? props : { ...props, key });", "export const jsxs = jsx; export const jsxDEV = jsx;"].join(" ");
  const dataUrl = value => "data:text/javascript," + encodeURIComponent(value);
  const script = document.createElement("script");
  script.type = "importmap";
  script.textContent = JSON.stringify({
    imports: {
      react: dataUrl(source),
      "react/jsx-runtime": dataUrl(jsx),
      "react/jsx-dev-runtime": dataUrl(jsx)
    }
  });
  document.head.appendChild(script);
  window.__OA_SHARED_REACT__ = true;
};

export const MODULE_SPECS = {
  sdk: () => CDN("@rhinestone/1auth@" + SDK_VERSION),
  viem: () => CDN("viem@" + VIEM_VERSION)
};

export const importModule = url => new Promise((resolve, reject) => {
  const key = "__oa_" + Math.random().toString(36).slice(2);
  window[key] = {
    resolve,
    reject
  };
  const script = document.createElement("script");
  script.type = "module";
  script.textContent = "import(" + JSON.stringify(url) + ").then(m => window[" + JSON.stringify(key) + "].resolve(m))" + ".catch(e => window[" + JSON.stringify(key) + "].reject(new Error(String(e))));";
  script.onerror = () => reject(new Error("failed to load " + url));
  document.head.appendChild(script);
  script.remove();
});

export const importModuleWithRetry = async url => {
  try {
    return await importModule(url);
  } catch (first) {
    await new Promise(r => setTimeout(r, 500));
    return importModule(url);
  }
};

export const loadDeps = async () => {
  shareReact();
  const specs = Object.entries(MODULE_SPECS).map(([name, spec]) => [name, spec()]);
  const cacheKey = "__OA_DEPS__" + specs.map(([, url]) => url).join("|");
  if (window[cacheKey]) return window[cacheKey];
  const loaded = await Promise.all(specs.map(([, url]) => importModuleWithRetry(url)));
  const deps = {
    React
  };
  specs.forEach(([name], i) => {
    deps[name] = loaded[i];
  });
  deps.motion = motionShim();
  window[cacheKey] = deps;
  return deps;
};

export const unreachable = call => "Sponsorship " + call + " never reached " + backends().sponsorship + ". The browser hides why: a rejected origin, a failed preflight and a network" + " error all look identical here. The failing request is in the console.";

export const sponsorship = {
  accessToken: async () => {
    let res;
    try {
      res = await fetch(backends().sponsorship + "/access-token", {
        method: "GET",
        credentials: "include"
      });
    } catch (e) {
      throw new Error(unreachable("access token"));
    }
    if (!res.ok) throw new Error("Sponsorship access token failed (" + res.status + ")");
    return (await res.json()).token;
  },
  getExtensionToken: async intentOp => {
    let res;
    try {
      res = await fetch(backends().sponsorship + "/extension-token", {
        method: "POST",
        credentials: "include",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify({
          intentOp
        })
      });
    } catch (e) {
      throw new Error(unreachable("extension token"));
    }
    if (!res.ok) throw new Error("Sponsorship extension token failed (" + res.status + ")");
    return (await res.json()).token;
  }
};

export const motionShim = () => {
  const passthrough = Tag => React.forwardRef((props, ref) => {
    const rest = Object.fromEntries(Object.entries(props).filter(([k]) => !["initial", "animate", "exit", "transition", "variants", "whileHover", "whileTap", "layout", "layoutId"].includes(k)));
    return React.createElement(Tag, {
      ...rest,
      ref
    });
  });
  const cache = {};
  return {
    motion: new Proxy({}, {
      get: (_, tag) => {
        if (!cache[tag]) cache[tag] = passthrough(tag);
        return cache[tag];
      }
    }),
    AnimatePresence: ({children}) => React.createElement(React.Fragment, null, children),
    useReducedMotion: () => true
  };
};

export const AuthContext = React.createContext(null);

export const useAuthContext = () => React.useContext(AuthContext);

export const buildModules = deps => {
  const mods = {};
  mods.authctx = (() => {
    const DOCS_APP_ORIGIN_STORAGE_KEY = STORAGE_KEY;
    const useAuth = () => useAuthContext();
    return {
      DOCS_APP_ORIGIN_STORAGE_KEY,
      useAuth,
      clearDocsSession: () => {}
    };
  })();
  mods.constants = (() => {
    const DOCS_APP_ORIGIN_CLIENT_ID = "docs-app-origin";
    function docsAppOriginWebAuthn() {
      if (typeof window === "undefined" || window.location.protocol !== "https:") {
        return {
          mode: "app_origin"
        };
      }
      return {
        mode: "app_origin",
        rpId: window.location.hostname
      };
    }
    const DOCS_EXPERIMENTAL_CLEAR_SIGNING = true;
    const APP_ORIGIN_DEMO_CAPABILITIES = {
      payButton: true,
      eip1193Transactions: true,
      sendCalls: true,
      batchCalls: true,
      messageSigning: true,
      typedDataSigning: true,
      batchIntents: true,
      smartSessions: true,
      walletConnection: true,
      recovery: true
    };
    const DOCS_DIALOG_THEME = {
      mode: "dark",
      accent: "#ffffff",
      backdrop: {
        color: "#52525c",
        opacity: 0.5,
        blur: 12
      }
    };
    const MOCK_USD_ADDRESS = "0x2f6fdE5E2AeAB6335d8f978B4d8B2a9c1129AcFb";
    const RECIPIENT_ADDRESS = "0x180b791BD181DF1773E4e33cb0374b258936d186";
    const MOCK_RWA_ADDRESS = "0x5948C7E284174f6Df0f2505fb3CBFbd685154323";
    const MOCK_SWAP_ADDRESS = "0xf2DFDC35d46e62F6D026afa36Cc6e941174B67f1";
    const MOCK_NFT_V2_ADDRESS = "0x99CCb273351Cf13713F7Bf5A0716d7C2a3DD4712";
    const MOCK_NFT_LUIGI_ID = 1n;
    const NVDA_ICON_SVG = `<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="250" height="250" fill="#76B900"/><path d="M99.5748 98.4439V86.5224C100.752 86.4488 101.93 86.3752 103.107 86.3752C135.781 85.345 157.195 114.486 157.195 114.486C157.195 114.486 134.088 146.571 109.289 146.571C105.977 146.571 102.739 146.056 99.6484 145.026V108.82C112.379 110.365 114.955 115.958 122.535 128.689L139.534 114.413C139.534 114.413 127.097 98.1495 106.198 98.1495C103.99 98.0759 101.782 98.2231 99.5748 98.4439ZM99.5748 59V76.8086L103.107 76.5878C148.512 75.0425 178.168 113.824 178.168 113.824C178.168 113.824 144.17 155.181 108.773 155.181C105.683 155.181 102.666 154.887 99.6484 154.372V165.41C102.15 165.705 104.726 165.925 107.228 165.925C140.196 165.925 164.039 149.073 187.146 129.204C190.973 132.295 206.647 139.727 209.885 142.965C187.956 161.363 136.811 176.154 107.817 176.154C105.02 176.154 102.371 176.007 99.722 175.713V191.24H224.971V59L99.5748 59ZM99.5748 145.026V154.445C69.1088 149 60.646 117.283 60.646 117.283C60.646 117.283 75.2903 101.093 99.5748 98.4439V108.746H99.5012C86.7702 107.201 76.7621 119.122 76.7621 119.122C76.7621 119.122 82.4285 139.212 99.5748 145.026ZM45.4866 115.958C45.4866 115.958 63.516 89.3188 99.6484 86.5224V76.8086C59.6158 80.0465 25.0288 113.898 25.0288 113.898C25.0288 113.898 44.6036 170.561 99.5748 175.713V165.41C59.2478 160.406 45.4866 115.958 45.4866 115.958Z" fill="white"/></svg>`;
    const NVDA_ICON_DATA_URL = `data:image/svg+xml;utf8,${encodeURIComponent(NVDA_ICON_SVG)}`;
    const LUIGI_ICON_SVG = `<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" fill="none" viewBox="0 0 28 28"><rect width="28" height="28" fill="#32a742" rx="4"/><path fill="#101110" d="M13 5.4h.9a7 7 0 0 1 4 1.1q1.3 1 2 2.4l.3.5.5-.6L22 7.5q1-.9 2.2-1.3h.5l.4.3v.8a9 9 0 0 1-2.5 4.4l-.6.6q.6.7.2 1.7t-1.4 1.6l.2.8q.4 2-.5 3.6l-.4.5a8 8 0 0 1-5.7 2.1h-1l-1.8-.3-.5-.2-.9-.3q-1-.4-1.8-1.2-.6-.6-1-1.4a5 5 0 0 1 0-3.6q-.9-.3-1.3-.9-.5-.9-.1-2v-.1L3.8 10q-.9-1.3-1-2.8 0-.5.3-.6C4 6.6 6 8 6.8 8.8l.9.9q.4-1 1.1-2c1.2-1.5 2.3-2 4.2-2.3"/><path fill="#f7c30f" d="M8.5 14q1.1.7 2.4.5c1-.2 2.3-1 3.3-.9l1.6.4.3.1.6.2q1.6.4 2.8-.5l.2.2c.8 1.3 1.5 3.3 1 4.8l-.5 1c0 .2-.7.8-.9.9l-.3.2-.3.2q-.6.5-1.3.6a9 9 0 0 1-7.6-.4l-.5-.4-.6-.4-.6-.7-.4-.7c-.5-.8-.4-2.4-.1-3.2q.1-.8.6-1.4l.1-.2z"/><path fill="#fb9410" d="M17.7 20.8q0 .3.4.3h.6q-.6.5-1.3.6a9 9 0 0 1-7.6-.4q.5 0 .9-.3 3.4.9 6.7 0z"/><path fill="#e0051c" d="M17.6 20.2c.2-1.5 2.6-3 2.8-1.5h.3l-.5 1.1c0 .2-.7.8-.9.9l-.3.2-.3.2H18q-.3 0-.4-.3z"/><path fill="#870c0d" d="M17.6 20.2c.2-1.5 2.6-3 2.8-1.5h.3l-.5 1.1c0 .2-.7.8-.9.9l.4-.5q.6-.7.6-1.5l-.3-.1h-.8q-.6.4-1 1l-.4.4h-.1z"/><path fill="#fb99a0" d="m17.8 20 .3-.7c.4-.6 1.3-1.4 2-1l.2.4-.3-.1h-.8q-.6.4-1 1z"/><path fill="#fac550" d="M20.4 18.7h.3l-.5 1.1v-.2q.3-.5.2-.9"/><path fill="#870c0d" d="m17.6 20.2.1-.1q-.1.6.4.9h.6l.3-.1-.3.2H18q-.3 0-.4-.3z"/><path fill="#e0051c" d="M7.9 19q0-.7.7-.7c1 0 2.5 1.7 2 2.7q-.2.4-.8.3l-.5-.4-.6-.4-.6-.7-.4-.7z"/><path fill="#870c0d" d="M7.9 19q0-.7.7-.7c1 0 2.5 1.7 2 2.7q-.2.4-.8.3l-.5-.4c.4 0 .4.3 1 .2l.3-.3q0-.5-.2-.9l-.5-.6Q9 18.4 8 19l.2.9-.1-.2v.2l-.4-.7z"/><path fill="#fb99a0" d="M8 18.9q.2-.6.8-.5a3 3 0 0 1 1.7 1.5l-.6-.6Q9 18.4 8 19"/><path fill="#fac550" d="M7.7 19h.2q0 .4.2.6v.2z"/><path fill="#831218" d="m8 19.6.2.2q.4.3.5.7l-.6-.7z"/><path fill="#101110" d="M17.4 14.9h.7q1.2.8.6 2v.1q-.4.5-1 .6-.8-.2-1-.8-.3-.6 0-1.2t.7-.7"/><path fill="#f2f0ee" d="M17.3 15.2q.3 0 .5.2v.3q0 .3-.3.3-.4 0-.5-.2-.2-.5.3-.6"/><path fill="#fb9410" d="M8.5 14q1.1.7 2.4.5c1-.2 2.3-1 3.3-.9l1.6.4.3.1.6.2q1.6.4 2.8-.5l.2.2-.6.5-.7.3H18v.1h-.6c0-.2-.8-.2-1-.2q-1.3-.4-2.7-.6l-1.3.3c-1.8.5-2.3.7-4 0l-.1-.1z"/><path fill="#fac550" d="m8.3 14.3-.1.2h-.1z"/><path fill="#101110" d="m14.1 17.6.3.1a5 5 0 0 0 2.8.3l.6-.1.1.2c.1 1.7-1.6 2.1-3 1.8l-.8-.3-.4.1-.7.3-1.2-.1c-.7-.2-1.6-.9-1.3-1.7q0-.2.3 0 1.7.4 3.3-.6M10.2 15c1.6-.2 1.9 2.3.4 2.7l-.6-.1c-1.1-.5-1-2.4.2-2.6"/><path fill="#f2f0ee" d="M10.6 15.3q.3 0 .5.2v.4q0 .2-.3.2h-.2l-.3-.2q-.2-.5.3-.6"/><path fill="#101110" d="m14 17.2.3.1v.2q-.5 0-.4-.3"/><path fill="#008a4d" d="M8.4 10.7 8 10c-.1-.2.3-.9.4-1A6 6 0 0 1 11 6.3c1.5-.7 3.5-.8 5-.2q2.2.7 3.3 2.6.4.4.6 1l-.2.3-.5.8-.7 1.2-.7-.4 1 1.2-.6-.5a7 7 0 0 0-2.3-1q.7-1 .5-2t-1-1.5a3 3 0 0 0-4 .7c-.4.8-.4 2 .2 2.7l.2.2-1.5.6-.8.5v-.2l.3-.4.1-.3-.2.1-.4.4V12z"/><path fill="#80c491" d="M8.4 10.7 8 10c-.1-.2.3-.9.4-1A6 6 0 0 1 11 6.3c1.5-.7 3.5-.8 5-.2q2.2.7 3.3 2.6.4.4.6 1l-.2.3v-.2l-.7-.9q-.7-1-1.7-2a6 6 0 0 0-2.8-1 6 6 0 0 0-4.6 2c-.5.5-1.3 2-1.6 2.8"/><path fill="#064634" d="m19.7 9.8.1.2-.5.8-.7 1.2q-.4-.4-.7-.4l1 1.2-.6-.5-1-.5.1-.4q.3-.3 1-.4.9-.3 1.3-1.2"/><path fill="#80c491" d="M10 11.6h.3l-.4.3zm-.7.4.5-.3z"/><path fill="#008a4d" d="M9.6 12.9a7 7 0 0 1 6.8-1.2l1 .4a7 7 0 0 1 2 1.5c-.8.7-2 .5-2.8.3q-.6 0-1-.3c-1.4-.4-1.7-.5-3 0l-1.8.6a3 3 0 0 1-2.2-.5z"/><path fill="#064634" d="M17.3 12.1a7 7 0 0 1 2 1.5c-.7.7-1.8.5-2.7.3.8-.6 1-.7.7-1.8"/><path fill="#80c491" d="M9.6 12.9c.1.5-.1.5.4 1s2.3-.4 2.5-.3q-.8.4-1.7.6a3 3 0 0 1-2.2-.5z"/><path fill="#f2f0ee" d="M13.8 7.6q1 0 1.8.6 1.5 1.4.1 3a9 9 0 0 0-3.6.1q-.6-.5-.7-1.3.1-2.3 2.4-2.4"/><path fill="#008a4d" d="m13.6 8-.1 2h1.6v.8h-2.3V8z"/><path fill="#fb9410" d="m18.8 12.3.3-.7q1-1.7 2.4-3.2l.7-.7.2.3 1 2.4-3 2.9-.6.4-.8-1.3z"/><path fill="#f7c30f" d="m18.8 12.3.3-.7q1-1.7 2.4-3.2l.7-.7.2.3.3.8-.8.5-.7.5-1 1-.9.8z"/><path fill="#fbeca3" d="m18.8 12.3.3-.7q1-1.7 2.4-3.2l.7-.7.2.3-.3.3a14 14 0 0 0-2.5 2.9l-.3.4z"/><path fill="#fb9410" d="M5.4 8.1q2 1.5 3.3 3.6l.5.7-.1.2q-.6.5-.8 1.2l-.8-.5q-1.6-1.1-3-2.7l.7-2.1z"/><path fill="#f7c30f" d="M5.4 8.1q2 1.5 3.3 3.6l.5.7-.1.2H9l-.6-.8-1.5-1.6-.7-.5-1-.7H5z"/><path fill="#fbeca3" d="M5.4 8.1a14 14 0 0 1 3.4 3.7h-.1C8.2 11 6 8.9 5.3 8.5z"/><path fill="#fac550" d="m8.7 11.7.5.7-.1.2v-.3z"/><path fill="#064634" d="M21.7 12.5c.7 1.1 0 2.2-1 2.8l-.2-.3-.5-1zm-15.4.3 1.2.9.6.4-.5.9-.2.3q-.8-.3-1.2-1.1-.2-.8 0-1.4"/><path fill="#f2f0ee" d="M24.3 6.5h.4l-.5.4-1.5.9h-.2l-.1-.2a5 5 0 0 1 1.9-1.1M3.2 7a6 6 0 0 1 2 1v.2H5l-.8-.4L3 7.3z"/><path fill="#1f5e4c" d="m9.3 12.7.3-.4v.1z"/></svg>`;
    const LUIGI_ICON_DATA_URL = `data:image/svg+xml;utf8,${encodeURIComponent(LUIGI_ICON_SVG)}`;
    const MUSD_ICON_SVG = `<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0_4758_159829)"><g filter="url(#filter0_i_4758_159829)"><path d="M124.999 249.149C193.565 249.149 249.149 193.565 249.149 124.999C249.149 56.4325 193.565 0.848633 124.999 0.848633C56.4325 0.848633 0.848633 56.4325 0.848633 124.999C0.848633 193.565 56.4325 249.149 124.999 249.149Z" fill="white"/></g><path d="M101.7 211.35C101.7 214.25 99.3499 215.9 96.6499 215.05C59.0499 203 31.8999 167.85 31.8999 126.25C31.8999 84.7497 59.0499 49.5497 96.6999 37.4997C99.4999 36.6497 101.75 38.2997 101.75 41.1997V48.4497C101.75 50.3997 100.3 52.5997 98.4499 53.2997C68.6499 64.2497 47.4499 92.8497 47.4499 126.25C47.4499 159.7 68.6999 188.25 98.4499 199.1C100.3 199.8 101.75 202 101.75 203.95V211.35H101.7Z" fill="black"/><path d="M132.752 184.451C132.752 186.601 131.002 188.351 128.852 188.351H121.102C118.952 188.351 117.202 186.601 117.202 184.451V172.251C100.252 169.901 92.0016 160.501 89.7516 147.501C89.3516 145.251 91.1016 143.351 93.3516 143.351H102.202C104.052 143.351 105.602 144.701 106.002 146.451C107.652 154.101 112.102 160.051 125.702 160.051C135.702 160.051 142.852 154.401 142.852 146.101C142.852 137.751 138.702 134.551 123.952 132.151C102.202 129.251 91.9516 122.651 91.9516 105.651C91.9516 92.5512 101.952 82.2512 117.252 80.1512V68.1012C117.252 65.9512 119.002 64.2012 121.152 64.2012H128.902C131.052 64.2012 132.802 65.9512 132.802 68.1012V80.4012C145.302 82.6512 153.252 89.7012 155.902 101.551C156.402 103.801 154.652 105.801 152.302 105.801H144.152C142.402 105.801 140.952 104.651 140.452 103.001C138.202 95.5512 132.902 92.2512 123.552 92.2512C113.252 92.2512 107.952 97.2012 107.952 104.201C107.952 111.551 110.952 115.251 126.752 117.501C148.102 120.401 159.152 126.501 159.152 144.651C159.152 158.401 148.852 169.601 132.852 172.101V184.501H132.752V184.451Z" fill="black"/><path d="M153.3 214.997C150.5 215.847 148.25 214.197 148.25 211.297V204.047C148.25 201.897 149.5 199.897 151.55 199.197C181.25 188.347 202.55 159.697 202.55 126.347C202.55 92.897 181.3 64.347 151.55 53.497C149.7 52.797 148.25 50.597 148.25 48.647V41.397C148.25 38.497 150.6 36.847 153.3 37.697C190.95 49.547 218.1 84.747 218.1 126.247C218.1 167.847 190.95 202.997 153.3 214.997Z" fill="black"/></g><defs><filter id="filter0_i_4758_159829" x="0.848633" y="0.848633" width="248.3" height="248.3" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/><feOffset/><feGaussianBlur stdDeviation="41.5"/><feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/><feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/><feBlend mode="normal" in2="shape" result="effect1_innerShadow_4758_159829"/></filter><clipPath id="clip0_4758_159829"><rect width="250" height="250" fill="white"/></clipPath></defs></svg>`;
    const MUSD_ICON_DATA_URL = `data:image/svg+xml;utf8,${encodeURIComponent(MUSD_ICON_SVG)}`;
    const USDC_BASE_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
    const USDC_BASE_SEPOLIA_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
    const USDC_ARB_SEPOLIA_ADDRESS = "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d";
    const BASE_SEPOLIA_CHAIN_ID = 84532;
    const ARB_SEPOLIA_CHAIN_ID = 421614;
    const erc20Abi = [{
      name: "transfer",
      type: "function",
      stateMutability: "nonpayable",
      inputs: [{
        name: "to",
        type: "address"
      }, {
        name: "amount",
        type: "uint256"
      }],
      outputs: [{
        name: "",
        type: "bool"
      }]
    }, {
      name: "approve",
      type: "function",
      stateMutability: "nonpayable",
      inputs: [{
        name: "spender",
        type: "address"
      }, {
        name: "amount",
        type: "uint256"
      }],
      outputs: [{
        name: "",
        type: "bool"
      }]
    }, {
      name: "mint",
      type: "function",
      stateMutability: "nonpayable",
      inputs: [{
        name: "to",
        type: "address"
      }, {
        name: "amount",
        type: "uint256"
      }],
      outputs: []
    }, {
      name: "balanceOf",
      type: "function",
      inputs: [{
        name: "account",
        type: "address"
      }],
      outputs: [{
        name: "",
        type: "uint256"
      }],
      stateMutability: "view"
    }];
    const mockSwapAbi = [{
      name: "swap",
      type: "function",
      stateMutability: "nonpayable",
      inputs: [{
        name: "usdcIn",
        type: "uint256"
      }, {
        name: "minRwaOut",
        type: "uint256"
      }, {
        name: "recipient",
        type: "address"
      }],
      outputs: [{
        name: "rwaOut",
        type: "uint256"
      }]
    }, {
      name: "quote",
      type: "function",
      stateMutability: "view",
      inputs: [{
        name: "usdcIn",
        type: "uint256"
      }],
      outputs: [{
        name: "rwaOut",
        type: "uint256"
      }]
    }, {
      name: "getPrice",
      type: "function",
      stateMutability: "view",
      inputs: [],
      outputs: [{
        name: "price",
        type: "uint256"
      }]
    }, {
      name: "pricePerShare",
      type: "function",
      stateMutability: "view",
      inputs: [],
      outputs: [{
        name: "",
        type: "uint256"
      }]
    }, {
      name: "jitterRange",
      type: "function",
      stateMutability: "view",
      inputs: [],
      outputs: [{
        name: "",
        type: "uint256"
      }]
    }];
    const mockNftV2Abi = [{
      name: "buy",
      type: "function",
      stateMutability: "nonpayable",
      inputs: [{
        name: "id",
        type: "uint256"
      }, {
        name: "amount",
        type: "uint256"
      }, {
        name: "recipient",
        type: "address"
      }],
      outputs: [{
        name: "totalPrice",
        type: "uint256"
      }]
    }, {
      name: "priceOf",
      type: "function",
      stateMutability: "view",
      inputs: [{
        name: "id",
        type: "uint256"
      }],
      outputs: [{
        name: "",
        type: "uint256"
      }]
    }];
    return {
      docsAppOriginWebAuthn,
      DOCS_APP_ORIGIN_CLIENT_ID,
      DOCS_EXPERIMENTAL_CLEAR_SIGNING,
      APP_ORIGIN_DEMO_CAPABILITIES,
      DOCS_DIALOG_THEME,
      MOCK_USD_ADDRESS,
      RECIPIENT_ADDRESS,
      MOCK_RWA_ADDRESS,
      MOCK_SWAP_ADDRESS,
      MOCK_NFT_V2_ADDRESS,
      MOCK_NFT_LUIGI_ID,
      NVDA_ICON_DATA_URL,
      LUIGI_ICON_DATA_URL,
      MUSD_ICON_DATA_URL,
      USDC_BASE_ADDRESS,
      USDC_BASE_SEPOLIA_ADDRESS,
      USDC_ARB_SEPOLIA_ADDRESS,
      BASE_SEPOLIA_CHAIN_ID,
      ARB_SEPOLIA_CHAIN_ID,
      erc20Abi,
      mockSwapAbi,
      mockNftV2Abi
    };
  })();
  mods.mintBanner = (() => {
    const {useState, useCallback, useMemo, useEffect} = deps.React;
    const {createOneAuthProvider} = deps.sdk;
    const {encodeFunctionData, parseUnits} = deps.viem;
    const {DOCS_APP_ORIGIN_STORAGE_KEY, useAuth} = mods.authctx;
    const {MOCK_USD_ADDRESS, BASE_SEPOLIA_CHAIN_ID, erc20Abi} = mods.constants;
    const BASE_SEPOLIA_RPC = "https://sepolia.base.org";
    const callsOutcome = function callsOutcome2(result) {
      const intentStatus = String(result?.intentStatus ?? "").toLowerCase();
      if (intentStatus === "completed") return "success";
      if (intentStatus === "failed" || intentStatus === "expired") return "failed";
      if (!result || String(result.status).toUpperCase() !== "CONFIRMED") {
        return "pending";
      }
      const receipts = Array.isArray(result.receipts) ? result.receipts : [];
      if (receipts.length === 0) return "pending";
      const statuses = receipts.map(receipt => String(receipt?.status ?? "").toLowerCase());
      if (statuses.includes("0x0")) return "failed";
      return statuses.every(status => status === "0x1") ? "success" : "pending";
    };
    const isIntentLookupFailure = function isIntentLookupFailure2(result) {
      const code = String(result?.error?.code ?? "").toUpperCase();
      return code === "STATUS_FAILED" || code === "NETWORK_ERROR";
    };
    const readCallsStatus = async function readCallsStatus2(provider, client, id) {
      const result = await provider.request({
        method: "wallet_getCallsStatus",
        params: [id]
      });
      const receipts = Array.isArray(result?.receipts) ? result.receipts : null;
      if (String(result?.status).toUpperCase() !== "CONFIRMED" || !receipts || receipts.length > 0) {
        return result;
      }
      const intent = await client.getIntentStatus(id);
      if (isIntentLookupFailure(intent)) {
        throw new Error(intent.error?.message ?? "Status check failed");
      }
      return {
        ...result,
        intentStatus: intent?.status,
        transactionHash: result?.transactionHash ?? intent?.transactionHash
      };
    };
    function getStoredUser() {
      try {
        const saved = localStorage.getItem(DOCS_APP_ORIGIN_STORAGE_KEY);
        if (saved) return JSON.parse(saved);
      } catch {}
      return {};
    }
    function resolveAddress() {
      const stored = getStoredUser();
      return stored.address ?? null;
    }
    async function checkOnChainBalance(address) {
      const data = encodeFunctionData({
        abi: erc20Abi,
        functionName: "balanceOf",
        args: [address]
      });
      const res = await fetch(BASE_SEPOLIA_RPC, {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify({
          jsonrpc: "2.0",
          method: "eth_call",
          params: [{
            to: MOCK_USD_ADDRESS,
            data
          }, "latest"],
          id: 1
        })
      });
      const json = await res.json();
      return json.result ? BigInt(json.result) : 0n;
    }
    function MintBanner() {
      const {client, isAuthenticated} = useAuth();
      const [state, setState] = useState("idle");
      const [error, setError] = useState(null);
      const [callsId, setCallsId] = useState(null);
      const requiredBalance = useMemo(() => parseUnits("1", 6), []);
      const provider = useMemo(() => createOneAuthProvider({
        client,
        chainId: BASE_SEPOLIA_CHAIN_ID,
        storageKey: DOCS_APP_ORIGIN_STORAGE_KEY,
        waitForHash: false
      }), [client]);
      const checkBalance = useCallback(async () => {
        setState("checking");
        try {
          const address = resolveAddress();
          if (!address) {
            setState("insufficient");
            return;
          }
          const balance = await checkOnChainBalance(address);
          setState(balance >= requiredBalance ? "sufficient" : "insufficient");
        } catch {
          setState("insufficient");
        }
      }, [requiredBalance]);
      useEffect(() => {
        if (!isAuthenticated || !client) {
          setState("idle");
          return;
        }
        checkBalance();
      }, [isAuthenticated, client, checkBalance]);
      const handleMint = useCallback(async () => {
        setState("minting");
        setError(null);
        let submittedId = null;
        try {
          const accounts = await provider.request({
            method: "eth_requestAccounts"
          });
          const address = accounts[0];
          const mintData = encodeFunctionData({
            abi: erc20Abi,
            functionName: "mint",
            args: [address, parseUnits("1", 6)]
          });
          const mockUsdIcon = "https://s3.rhinestone.dev/tokens/musd.svg";
          const id = await provider.request({
            method: "wallet_sendCalls",
            params: [{
              chainId: BASE_SEPOLIA_CHAIN_ID,
              sourceChainId: BASE_SEPOLIA_CHAIN_ID,
              calls: [{
                to: MOCK_USD_ADDRESS,
                data: mintData,
                label: "Mint",
                sublabel: "1 mUSD",
                icon: mockUsdIcon
              }]
            }]
          });
          submittedId = id;
          setCallsId(id);
          const latest = await readCallsStatus(provider, client, id);
          const outcome = callsOutcome(latest);
          if (outcome === "success") {
            setState("success");
          } else if (outcome === "failed") {
            setError("Mint transaction failed onchain");
            setState("insufficient");
          } else {
            setState("pending");
          }
        } catch (err) {
          setError(err instanceof Error ? err.message : "Mint failed");
          setState(submittedId ? "pending" : "insufficient");
        }
      }, [provider, client]);
      const handleCheckMint = useCallback(async () => {
        if (!callsId) return;
        setError(null);
        try {
          const latest = await readCallsStatus(provider, client, callsId);
          const outcome = callsOutcome(latest);
          if (outcome === "success") setState("success"); else if (outcome === "failed") {
            setError("Mint transaction failed onchain");
            setState("insufficient");
          } else setState("pending");
        } catch (err) {
          setError(err instanceof Error ? err.message : "Status check failed");
        }
      }, [provider, client, callsId]);
      if (state === "idle" || state === "checking") return null;
      return React.createElement("div", {
        className: "demo-result demo-mint-banner",
        style: {
          marginTop: 0,
          marginBottom: "0.75rem"
        }
      }, state === "insufficient" && React.createElement(React.Fragment, null, React.createElement("p", {
        className: "demo-result-label"
      }, "No mUSD Balance"), React.createElement("p", {
        className: "demo-result-value",
        style: {
          fontSize: "0.8rem"
        }
      }, "This demo requires mUSD on Base Sepolia. Mint some to get started."), React.createElement("button", {
        onClick: handleMint,
        className: "demo-button",
        style: {
          marginTop: "0.5rem"
        }
      }, "Mint 1 mUSD")), state === "minting" && React.createElement("p", {
        className: "demo-result-value",
        style: {
          fontSize: "0.8rem"
        }
      }, "Minting mUSD..."), state === "pending" && React.createElement(React.Fragment, null, React.createElement("p", {
        className: "demo-result-label"
      }, "Mint submitted"), React.createElement("p", {
        className: "demo-result-value",
        style: {
          fontSize: "0.75rem"
        }
      }, callsId), React.createElement("button", {
        onClick: handleCheckMint,
        className: "demo-button",
        style: {
          marginTop: "0.5rem"
        }
      }, "Check status")), state === "success" && React.createElement(React.Fragment, null, React.createElement("p", {
        className: "demo-result-value",
        style: {
          fontSize: "0.8rem",
          color: "#22c55e"
        }
      }, "1 mUSD mint confirmed."), React.createElement("button", {
        onClick: checkBalance,
        className: "demo-button-secondary",
        style: {
          marginTop: "0.5rem"
        }
      }, "Refresh balance")), state === "sufficient" && React.createElement(React.Fragment, null, React.createElement("p", {
        className: "demo-result-value",
        style: {
          fontSize: "0.8rem"
        }
      }, "Funding available (last checked)."), React.createElement("button", {
        onClick: checkBalance,
        className: "demo-button-secondary",
        style: {
          marginTop: "0.5rem"
        }
      }, "Refresh balance")), error && React.createElement("p", {
        style: {
          fontSize: "0.75rem",
          color: "#ef4444",
          marginTop: "0.25rem"
        }
      }, error));
    }
    return {
      MintBanner
    };
  })();
  mods.sendCallsDemo = (() => {
    const {useState, useCallback, useMemo} = deps.React;
    const {createOneAuthProvider} = deps.sdk;
    const {encodeFunctionData, parseUnits} = deps.viem;
    const {DOCS_APP_ORIGIN_STORAGE_KEY, useAuth} = mods.authctx;
    const {MOCK_USD_ADDRESS, RECIPIENT_ADDRESS, erc20Abi} = mods.constants;
    const {MintBanner} = mods.mintBanner;
    const callsOutcome = function callsOutcome2(result) {
      const intentStatus = String(result?.intentStatus ?? "").toLowerCase();
      if (intentStatus === "completed") return "success";
      if (intentStatus === "failed" || intentStatus === "expired") return "failed";
      if (!result || String(result.status).toUpperCase() !== "CONFIRMED") {
        return "pending";
      }
      const receipts = Array.isArray(result.receipts) ? result.receipts : [];
      if (receipts.length === 0) return "pending";
      const statuses = receipts.map(receipt => String(receipt?.status ?? "").toLowerCase());
      if (statuses.includes("0x0")) return "failed";
      return statuses.every(status => status === "0x1") ? "success" : "pending";
    };
    const isIntentLookupFailure = function isIntentLookupFailure2(result) {
      const code = String(result?.error?.code ?? "").toUpperCase();
      return code === "STATUS_FAILED" || code === "NETWORK_ERROR";
    };
    const readCallsStatus = async function readCallsStatus2(provider, client, id) {
      const result = await provider.request({
        method: "wallet_getCallsStatus",
        params: [id]
      });
      const receipts = Array.isArray(result?.receipts) ? result.receipts : null;
      if (String(result?.status).toUpperCase() !== "CONFIRMED" || !receipts || receipts.length > 0) {
        return result;
      }
      const intent = await client.getIntentStatus(id);
      if (isIntentLookupFailure(intent)) {
        throw new Error(intent.error?.message ?? "Status check failed");
      }
      return {
        ...result,
        intentStatus: intent?.status,
        transactionHash: result?.transactionHash ?? intent?.transactionHash
      };
    };
    function SendCallsDemo() {
      const {client, isAuthenticated, login} = useAuth();
      const [callsId, setCallsId] = useState(null);
      const [status, setStatus] = useState(null);
      const [error, setError] = useState(null);
      const [loading, setLoading] = useState(null);
      const provider = useMemo(() => createOneAuthProvider({
        client,
        chainId: 84532,
        waitForHash: false,
        storageKey: DOCS_APP_ORIGIN_STORAGE_KEY
      }), [client]);
      const amount = useMemo(() => parseUnits("0.1", 6), []);
      const handleSendCalls = useCallback(async () => {
        if (callsId) return;
        setLoading("send");
        try {
          if (!isAuthenticated) {
            const activeAddress = await login();
            if (!activeAddress) return;
          }
          setError(null);
          setStatus(null);
          const transferData = encodeFunctionData({
            abi: erc20Abi,
            functionName: "transfer",
            args: [RECIPIENT_ADDRESS, amount]
          });
          const result = await provider.request({
            method: "wallet_sendCalls",
            params: [{
              chainId: 84532,
              sourceChainId: 84532,
              calls: [{
                to: MOCK_USD_ADDRESS,
                data: transferData
              }, {
                to: MOCK_USD_ADDRESS,
                data: transferData
              }],
              tokenRequests: [{
                token: MOCK_USD_ADDRESS,
                amount: amount * 2n
              }]
            }]
          });
          setCallsId(result);
        } catch (err) {
          setError(err instanceof Error ? err.message : "Send calls failed");
        } finally {
          setLoading(null);
        }
      }, [provider, amount, isAuthenticated, login, callsId]);
      const handleGetStatus = useCallback(async () => {
        if (!callsId) return;
        const requestedId = callsId;
        setLoading("status");
        setError(null);
        try {
          const result = await readCallsStatus(provider, client, requestedId);
          if (requestedId === callsId) setStatus(result);
        } catch (err) {
          setError(err instanceof Error ? err.message : "Failed to get status");
        } finally {
          setLoading(null);
        }
      }, [provider, client, callsId]);
      const outcome = callsOutcome(status);
      const handleClear = () => {
        if (outcome === "pending") return;
        setCallsId(null);
        setStatus(null);
        setError(null);
      };
      return React.createElement("div", {
        className: "demo-container"
      }, React.createElement(MintBanner, null), React.createElement("div", {
        className: "demo-result"
      }, React.createElement("p", {
        className: "demo-result-label"
      }, "Batch Calls (2 \xD7 0.1 mUSD transfers)"), React.createElement("pre", {
        className: "demo-result-value",
        style: {
          fontSize: "0.75rem",
          whiteSpace: "pre-wrap"
        }
      }, `{
      chainId: 84532,
      calls: [
        { to: mUSD, data: transfer(${RECIPIENT_ADDRESS.slice(0, 6)}..., 100000) },
        { to: mUSD, data: transfer(${RECIPIENT_ADDRESS.slice(0, 6)}..., 100000) }
      ],
      tokenRequests: [{ token: mUSD, amount: 200000 }]
    }`)), React.createElement("div", {
        style: {
          display: "flex",
          gap: "0.5rem",
          marginTop: "0.75rem"
        }
      }, React.createElement("button", {
        onClick: handleSendCalls,
        disabled: loading === "send" || Boolean(callsId),
        className: "demo-button"
      }, loading === "send" ? "Relaying..." : "Relay atomic calls"), callsId && React.createElement("button", {
        onClick: handleGetStatus,
        disabled: loading === "status",
        className: "demo-button-secondary"
      }, loading === "status" ? "Loading..." : "Check status"), callsId && outcome !== "pending" && React.createElement("button", {
        onClick: handleClear,
        disabled: Boolean(loading),
        className: "demo-button-secondary"
      }, "Clear")), callsId && React.createElement("div", {
        className: `demo-result ${outcome === "success" ? "demo-result-success" : outcome === "failed" ? "demo-result-error" : ""}`
      }, React.createElement("p", {
        className: "demo-result-label"
      }, "Calls ID (", outcome, ")"), React.createElement("p", {
        className: "demo-result-value",
        style: {
          fontSize: "0.75rem"
        }
      }, callsId)), status && React.createElement("div", {
        className: `demo-result ${outcome === "success" ? "demo-result-success" : outcome === "failed" ? "demo-result-error" : ""}`
      }, React.createElement("p", {
        className: "demo-result-label"
      }, outcome === "success" ? "Succeeded" : outcome === "failed" ? "Failed" : "Pending"), status.transactionHash && React.createElement("p", {
        className: "demo-result-value"
      }, status.transactionHash), status.receipts?.map(receipt => receipt.transactionHash && React.createElement("p", {
        key: receipt.transactionHash,
        className: "demo-result-value"
      }, receipt.transactionHash)), React.createElement("pre", {
        className: "demo-result-value",
        style: {
          fontSize: "0.75rem",
          whiteSpace: "pre-wrap"
        }
      }, JSON.stringify(status, null, 2))), error && React.createElement("div", {
        className: "demo-result demo-result-error"
      }, React.createElement("p", {
        className: "demo-result-label"
      }, "Error"), React.createElement("p", {
        className: "demo-result-value"
      }, error)));
    }
    return {
      SendCallsDemo
    };
  })();
  return mods;
};

export const ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;

export const readStoredAddressFromJsonEnvelope = () => {
  try {
    const raw = window.localStorage.getItem(STORAGE_KEY);
    if (!raw) return null;
    const parsed = JSON.parse(raw);
    const address = parsed && typeof parsed === "object" ? parsed.address : null;
    return typeof address === "string" && ADDRESS_RE.test(address) ? address : null;
  } catch {
    return null;
  }
};

export const writeStoredAddressAsJsonEnvelope = address => {
  window.localStorage.setItem(STORAGE_KEY, JSON.stringify({
    address
  }));
};

export const useOneAuth = deps => {
  const [address, setAddress] = React.useState(null);
  const [client, setClient] = React.useState(null);
  const mounted = React.useRef(false);
  const sessionGeneration = React.useRef(0);
  React.useEffect(() => {
    if (!deps) return;
    mounted.current = true;
    const restoreGeneration = ++sessionGeneration.current;
    const {OneAuthClient} = deps.sdk;
    const nextClient = new OneAuthClient({
      providerUrl: backends().auth,
      clientId: "docs-app-origin",
      webauthn: {
        mode: "app_origin",
        rpId: window.location.hostname
      },
      theme: {
        mode: "dark",
        accent: "#ffffff",
        backdrop: {
          color: "#52525c",
          opacity: 0.5,
          blur: 12
        }
      },
      experimental_clear_signing: true,
      recovery: {
        fallback: {
          type: "verified-identity"
        }
      },
      testnets: true,
      prewarm: true,
      sponsorship,
      onDisconnect: () => {
        if (!mounted.current) return;
        sessionGeneration.current += 1;
        window.localStorage.removeItem(STORAGE_KEY);
        setAddress(null);
      }
    });
    setClient(nextClient);
    const stored = readStoredAddressFromJsonEnvelope();
    if (stored) {
      nextClient.getSession().then(result => {
        if (!mounted.current || sessionGeneration.current !== restoreGeneration) return;
        const account = result.success ? result.session.accountAddress : null;
        if (account && ADDRESS_RE.test(account)) {
          writeStoredAddressAsJsonEnvelope(account);
          setAddress(account);
        } else {
          window.localStorage.removeItem(STORAGE_KEY);
          setAddress(null);
        }
      }).catch(() => {
        if (!mounted.current || sessionGeneration.current !== restoreGeneration) return;
        window.localStorage.removeItem(STORAGE_KEY);
        setAddress(null);
      });
    }
    return () => {
      mounted.current = false;
      sessionGeneration.current += 1;
    };
  }, [deps]);
  const login = React.useCallback(async () => {
    if (!client) return null;
    const generation = ++sessionGeneration.current;
    const result = await client.authenticate({
      oauthEnabled: false
    });
    if (!result.success) {
      if (result.error?.code === "USER_CANCELLED") return null;
      throw new Error(result.error?.message ?? "Authentication failed");
    }
    const account = result.session.accountAddress;
    if (!ADDRESS_RE.test(account)) throw new Error("Authentication returned an invalid account address");
    if (!mounted.current || sessionGeneration.current !== generation) return null;
    writeStoredAddressAsJsonEnvelope(account);
    setAddress(account);
    return account;
  }, [client]);
  const logout = React.useCallback(() => {
    sessionGeneration.current += 1;
    window.localStorage.removeItem(STORAGE_KEY);
    if (mounted.current) setAddress(null);
    if (client?.disconnect) client.disconnect();
  }, [client]);
  return React.useMemo(() => ({
    address,
    isAuthenticated: !!address,
    client,
    sponsorship,
    login,
    logout
  }), [address, client, login, logout]);
};

export const Frame = ({children, connected}) => <div className="oa-demo">
    <div className="oa-demo-head">
      <span className="oa-demo-title">Relay atomic calls</span>
      <span className="oa-demo-status">
        <span className="oa-demo-dot" data-state={connected ? "on" : "off"} />
        {connected ? "Signed in" : "Not connected"}
      </span>
    </div>
    <div className="oa-demo-body">{children}</div>
  </div>;

export const GuideDemo = () => {
  const [deps, setDeps] = React.useState(null);
  const [loadError, setLoadError] = React.useState("");
  const [connecting, setConnecting] = React.useState(false);
  React.useEffect(() => {
    let cancelled = false;
    loadDeps().then(d => !cancelled && setDeps(d)).catch(e => !cancelled && setLoadError(String(e.message ?? e)));
    return () => {
      cancelled = true;
    };
  }, []);
  const mods = React.useMemo(() => deps ? buildModules(deps) : null, [deps]);
  const auth = useOneAuth(deps);
  return <div className="not-prose rhinestone-1auth-demo" data-demo="relay-a-transaction">
      <style dangerouslySetInnerHTML={{
    __html: CSS
  }} />
      <AuthContext.Provider value={auth}>
        <Frame connected={auth.isAuthenticated}>
          {mods && auth.client && true && !auth.isAuthenticated ? <div>
              <button className="demo-button" disabled={connecting} onClick={async () => {
    setConnecting(true);
    setLoadError("");
    try {
      await auth.login();
    } catch (error) {
      setLoadError(String(error.message ?? error));
    } finally {
      setConnecting(false);
    }
  }}>{connecting ? "Signing in..." : "Sign in to try it"}</button>
              {loadError ? <p className="demo-error">{loadError}</p> : null}
            </div> : mods && (auth.client || false) ? React.createElement(mods.sendCallsDemo.SendCallsDemo, {
    key: auth.address
  }) : loadError ? <p className="demo-error">{loadError}</p> : <span className="oa-demo-skeleton" />}
        </Frame>
      </AuthContext.Provider>
    </div>;
};

Relay one or more contract calls on a single chain. Use [Send a transaction](/transactions/multichain/send-a-transaction) instead when the transaction must source funds from another chain or deliver tokens to the target chain.

## Define the calls

This example transfers 0.1 USDC from the account on Base Sepolia. Both wallet types use the same calldata. Calls run in order and revert together if one fails.

```ts theme={null}
import { encodeFunctionData, erc20Abi, parseUnits } from "viem";
import { baseSepolia } from "viem/chains";

const usdc = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
const recipient = "0xd8da6bf26964af9d7eed9e03e53415d37aa96045";
const amount = parseUnits("0.1", 6);

const calls = [
  {
    to: usdc,
    value: 0n,
    data: encodeFunctionData({
      abi: erc20Abi,
      functionName: "transfer",
      args: [recipient, amount],
    }),
  },
] as const;
```

## Send the transaction

<Tabs>
  <Tab title="Embedded wallet">
    Use `oneAuth` and the authenticated `accountAddress` from [Accounts](/wallets/embedded-wallets/accounts). These options are available in `@rhinestone/1auth` `0.10.1`.

    `sendIntent()` prepares the route, requests passkey approval, and submits the transaction. Set `sourceChainId` and `targetChain` to the same chain to keep funding and execution on Base Sepolia:

    ```ts {5,8,15} theme={null}
    import { oneAuth } from "./oneauth";

    const result = await oneAuth.sendIntent({
      accountAddress,
      targetChain: baseSepolia.id,
      sourceChainId: baseSepolia.id,
      sourceAssets: [usdc],
      calls: [...calls],
      sponsorshipMode: "required",
      experimental_clear_signing: true,
      closeOn: "completed",
      waitForHash: true,
    });

    if (!result.success) {
      throw new Error(result.error?.message ?? `Intent ended as ${result.status}`);
    }

    console.log(result.intentId, result.status, result.transactionHash);
    ```

    `experimental_clear_signing: true` shows Rhinestone's prepared-action review before passkey approval. By default, your application owns the review UI. See [Clear signing](/wallets/embedded-wallets/clear-signing) for the experimental review contract.

    `closeOn: "completed"` waits for completion rather than an earlier execution milestone. `waitForHash: true` also requests the onchain transaction hash. If a request times out, keep any returned `intentId` and check it with `oneAuth.getIntentStatus(intentId)` before sending again. Inspect `status`: a pending status is not a failed transaction, even when that status response has `success: false`.

    ### Choose who pays

    This example uses `sponsorshipMode: "required"`: sponsorship must succeed or the request fails. Set it to `"disabled"` for a user-paid quote, with enough USDC on Base Sepolia to cover fees as well as the transfer.

    Embedded wallets do not expose ranked quotes or per-category sponsorship controls through `sendIntent()`. See [Sponsor fees](/transactions/sponsorship/sponsor-fees) for funding modes and fallback behavior.

    ### Try atomic calls

    This sponsored testnet demo uses the embedded wallet provider's `wallet_sendCalls` to relay two 0.1 mUSD transfers on Base Sepolia. Sign in, mint mock tokens if needed, then approve both calls together. Unlike a [queue of intents](/transactions/multichain/send-a-transaction#try-a-non-atomic-queue), these calls execute in one transaction and revert together.

    A calls ID identifies the submission, not its outcome. Use **Check status** to inspect the receipts: `0x1` means success and `0x0` means failure, even when the overall status is `CONFIRMED`.

    <GuideDemo />
  </Tab>

  <Tab title="Custom signer">
    Use `account` from the [Custom signer quickstart](/wallets/custom-signer/quickstart) with `@rhinestone/sdk@2.16.1`. There is no separate `relayTransaction` SDK method: use `prepareTransaction`, `signTransaction`, and `submitTransaction` with `chain` to request a same-chain route.

    ### Prepare a same-chain route

    ```ts theme={null}
    const prepared = await account.prepareTransaction({
      chain: baseSepolia,
      calls: [...calls],
    });

    const quote = prepared.quotes.best;
    console.log(quote.cost.input, quote.cost.output, quote.cost.fees);
    ```

    `prepareTransaction` returns ranked intent routes. Review the recommended route's assets, fees, and expiry before requesting a signature. To select another route, pass its `intentId` to `signTransaction`; never combine a signature from one route with another route.

    ### Sign and submit

    ```ts theme={null}
    import { isExecutionError } from "@rhinestone/sdk/errors";

    const signed = await account.signTransaction(prepared, {
      intentId: quote.intentId,
    });
    const submitted = await account.submitTransaction(signed);

    try {
      const result = await account.waitForExecution(submitted);
      console.log(result.status, result.operations);
    } catch (error) {
      if (error instanceof Error && isExecutionError(error)) {
        console.error(error.message, error.traceId, error.context);
      }
      throw error;
    }
    ```

    `submitTransaction` returns after the orchestrator accepts the intent. That acceptance is not an onchain success. Keep the returned intent ID and call `waitForExecution` or query its status until it reaches a terminal outcome. Status queries can return `PENDING`; `waitForExecution` waits for a terminal result or throws.

    | Outcome     | Meaning                                                                                                                 |
    | ----------- | ----------------------------------------------------------------------------------------------------------------------- |
    | `PENDING`   | The intent was accepted and its same-chain operation is still processing.                                               |
    | `COMPLETED` | The operation was confirmed. Its entry includes the onchain transaction hash.                                           |
    | `FAILED`    | Execution failed. `waitForExecution` throws an execution error whose context includes the operation and failure reason. |

    If submission returns an uncertain network result, query the existing intent before preparing another one to avoid duplicate execution. If the quote expires before submission, prepare and sign a new route.

    ### Choose who pays

    The example above is user-paid, so the account also needs enough funds to cover the quoted fees. To sponsor execution, set `sponsored: true` during preparation:

    ```ts {4} theme={null}
    const prepared = await account.prepareTransaction({
      chain: baseSepolia,
      calls: [...calls],
      sponsored: true,
    });
    ```

    Only fee categories present in the selected route are charged. Sponsorship is decided while quoting; a rejected sponsored request does not silently become user-paid. Follow [Sponsor fees](/transactions/sponsorship/sponsor-fees) for selective categories, quote inspection, and fallback behavior.

    ### Restrict the fee asset

    `sourceAssets` is the list of balances the orchestrator may spend. In a call-only relay the only balance it spends is the fee repayment, so this pins which token pays:

    ```ts theme={null}
    const prepared = await account.prepareTransaction({
      chain: baseSepolia,
      calls: [...calls],
      sourceAssets: [usdc],
    });
    ```

    Use the native token's zero address to allow the account's native balance. A user-paid request fails at quote time when none of the named assets can cover the fee.

    ### Set the destination gas limit

    `gasLimit` is the gas the calls are quoted against. Without it, the quote assumes a conservative default of 1,000,000 units, so a small call is over-quoted:

    ```ts theme={null}
    const prepared = await account.prepareTransaction({
      chain: baseSepolia,
      calls: [...calls],
      gasLimit: 200_000n,
    });
    ```

    Estimate the calls and add headroom. A limit below actual usage makes execution run out of gas.

    ### Extend the fill deadline

    Same-chain routes carry a two-minute onchain fill deadline. `customDeadline` overrides it with an absolute Unix timestamp in seconds, which is useful when a user reviews the action before approving:

    ```ts theme={null}
    const prepared = await account.prepareTransaction({
      chain: baseSepolia,
      calls: [...calls],
      customDeadline: Math.floor(Date.now() / 1000) + 900,
    });
    ```

    The value must be between two minutes and 24 hours from now; anything outside that range is rejected while quoting. The quoted `expiresAt` tracks it. This option is same-chain only — crosschain routes cannot set it.

    ### Declare incoming funds

    `auxiliaryFunds` lets the route count a balance that has not landed yet but arrives before settlement. It works the same way here as for multichain transactions; see [Quote against incoming funds](/transactions/multichain/send-a-transaction#quote-against-incoming-funds).

    ### Other account types

    The same prepare, sign, and submit contract supports plain EOAs, EIP-7702 accounts, and the SDK's Nexus, Safe, Kernel, `Startale`, and HCA smart account providers. This guide uses the default Nexus account from the quickstart. A pre-signed native Safe transaction uses the separate Safe relay flow: see [Relay a Safe transaction](/transactions/relaying/relay-a-safe-transaction).

    For an EIP-7702 account, include its initialization signature while preparing and submit the resulting authorizations. Follow the [EIP-7702 transaction flow](/wallets/custom-signer/configuration/account-types/eip-7702).

    <Note>
      Recovery guardians cannot sign an intent. Use account owners or a compatible
      session key for this flow; guardians authorize recovery UserOperations only.
    </Note>
  </Tab>
</Tabs>
