# Instant Login (Account Abstracted)

This section explains how and why we the ERC-4337 “account abstraction” style login is used for Instant Actions. It will cover:

• What ERC-4337 and EIP-1271 bring to the table\
• The end-to-end flow for Instant Login (fetching a nonce, building a SIWE message, hashing/signing, local EIP-1271 validation, HTTP call)\
• A complete TypeScript code snippet showing how to call `/login` and obtain an access token

## Why ERC-4337 / Account Abstraction?

Traditional EOAs (Externally Owned Accounts) sign every transaction with their private key. Smart-contract wallets (Gnosis Safe, Argent, etc.) cannot expose a raw private key.\
ERC-4337 let’s a smart-contract wallet “`personal_sign`” arbitrary data off-chain, then verify that signature on-chain via the standard EIP-1271 `isValidSignature(bytes32, bytes)` call.

**Benefits for Instant Actions:**\
• Users grant a single “session” signature once.\
• Solvers can verify authorization on-chain or locally.\
• No need for the user to re-sign every open/close quote.

## High-Level Login Flow

1. Fetch a nonce from `/nonce/{subAccount}`
2. Construct a SIWE message (domain, wallet address, statement, nonce, issuedAt, expiration)
3. Apply EIP-191 prefix + keccak256 → “ERC-4337 hash”
4. Ask the Safe to personal\_sign the raw SIWE string (SigningMethod.ETH\_SIGN)
5. (Optional) Locally verify the signature via `protocolKit.isValidSignature(erc4337Hash, sig)`
6. POST to `/login` with\
   • `account_address`\
   • `issued_at`\
   • `expiration_time`\
   • `nonce`\
   • `signature` (packed Safe signatures)\
   • `sign_type: “ERC4337”`

{% hint style="info" %}
The `sign_type` field is essential to obtain an access token with Rasa but not necessarily required for other solvers.
{% endhint %}

Server validates on-chain via EIP-1271 and returns an access token

Use that token as\
Authorization: Bearer \<access\_token>\
for all subsequent instant open/close calls.

### Detailed Code Example (TypeScript)

```ts
import Safe, { hashSafeMessage }   from '@safe-global/protocol-kit'
import { SigningMethod }           from '@safe-global/types-kit'
import { ethers }                  from 'ethers'
import axios                       from 'axios'

async function main() {
  // ── Configuration ─────────────────────────────────────────
  const RPC_URL      = 'https://rpc.ankr.com/base/…'
  const SAFE_OWNER   = '0x…'    // your EOA private key
  const SAFE_ADDRESS = '0x…'    // your Safe contract
  const SUBACCOUNT   = '0x…'    // sub-account for login
  const SOLVER_BASE  = 'https://base-hedger82.rasa.capital'
  const DOMAIN       = 'localhost'
  const ORIGIN       = 'http://localhost:3000'
  const CHAIN_ID     = 8453

  // 1) initialize Safe SDK (this is the account compatible with ERC4337)
  const protocolKit = await Safe.init({
    provider:   RPC_URL,
    signer:     SAFE_OWNER,
    safeAddress: SAFE_ADDRESS
  })

  // 2) fetch nonce
  const nonce = await axios
    .get(`${SOLVER_BASE}/nonce/${SUBACCOUNT}`)
    .then(r => r.data.nonce)

  // 3) build SIWE message string (exactly same style as your code)
  const issuedAt       = new Date().toISOString()
  const expirationTime = new Date(Date.now() + 86_400_000).toISOString()
  const siweMessage = `${DOMAIN} wants you to sign in with your Ethereum account:
${SAFE_ADDRESS}

msg: ${SUBACCOUNT}

URI: ${SOLVER_BASE}/login
Version: 1
Chain ID: ${CHAIN_ID}
Nonce: ${nonce}
Issued At: ${issuedAt}
Expiration Time: ${expirationTime}`

  // 4) compute ERC‐4337/EIP-191 hash
  function encodeERC4337(msg: string): string {
    const hexMsg   = Buffer.from(msg, 'utf8').toString('hex')
    const prefix   = `\x19Ethereum Signed Message:\n${msg.length}`
    const prefixHex= Buffer.from(prefix, 'utf8').toString('hex')
    return ethers.keccak256('0x' + prefixHex + hexMsg)
  }
  const erc4337Hash = encodeERC4337(siweMessage)
  console.log('[ERC4337] message hash:', erc4337Hash)

  // 5) personal_sign via the Safe (EIP-191)
  const safeMsg   = protocolKit.createMessage(siweMessage)
  const signed    = await protocolKit.signMessage(
    safeMsg,
    SigningMethod.ETH_SIGN,   // personal_sign / EIP-191
    SAFE_ADDRESS
  )
  const signature = signed.encodedSignatures()

  // 6) local EIP-1271 validation (optional)
  const ok = await protocolKit.isValidSignature(erc4337Hash, signature)
  if (!ok) throw new Error('Local EIP-1271 check failed')

  // 7) send the login request
  const loginBody = {
    account_address:  SUBACCOUNT,
    issued_at:        issuedAt,
    expiration_time:  expirationTime,
    nonce,
    signature,
    sign_type:        'ERC4337'   // tell server “use EIP-1271 flow”
  }

  const resp = await axios.post(
    `${SOLVER_BASE}/login`,
    loginBody,
    {
      headers: {
        'Content-Type': 'application/json',
        Origin:          ORIGIN,
        Referer:         ORIGIN
      }
    }
  )

  console.log('Login response:', resp.data)
  // → { access_token: 'eyJ…' }
}

main().catch(console.error)

```

***

When the server receives your POST body, the solver backend will:

• Reconstruct the same SIWE message (using your domain, URI, nonce, subaccount, etc.)\
• Re-compute the ERC-4337 hash (EIP-191 prefix + keccak256)\
• Call `userSmartWallet.isValidSignature(hash, signature)` on-chain\
– If it returns `0x1626ba7e`, the signature is valid\
• If valid, mint you a JWT access\_token with an expiry and your sub-account embedded

Using Your Access Token

***

Once you have `access_token`, attach it to every instant-action request:

Authorization: Bearer \<access\_token>

The solver will trust that token (no further on-chain checks) until it expires.

You can see how to attach this token to requests in the [Building an Application with SYMMIO](/exchange-builder-documentation/frontend-builder-technical-guidance/instant-trading/sending-a-quote-instant-open.md) section.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.symm.io/exchange-builder-documentation/frontend-builder-technical-guidance/instant-trading/instant-login-account-abstracted.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
