Skip to main content
Authenticate users with Ethereum accounts.
import * as Siwe from 'voltaire-effect/primitives/Siwe'
import { Effect } from 'effect'

// Create message
const message = await Effect.runPromise(
  Siwe.create({
    domain: 'example.com',
    address: '0x1234567890123456789012345678901234567890',
    uri: 'https://example.com',
    chainId: 1,
    statement: 'Sign in to Example'
  })
)

// Format to string
const text = Siwe.format(message)

// Parse from string
const parsed = await Effect.runPromise(Siwe.parse(text))

// Validate (expiration, etc.)
const result = Siwe.validate(parsed)

// Generate nonce
const nonce = Siwe.generateNonce()  // 16 chars default

Schemas

import * as Schema from 'effect/Schema'

// Parse SIWE string
const message = Schema.decodeSync(Siwe.String)(`example.com wants you to sign in...`)

// Validate structure
const isValid = Schema.is(Siwe.MessageStruct)({
  domain: 'example.com',
  address: new Uint8Array(20),
  uri: 'https://example.com',
  version: '1',
  chainId: 1,
  nonce: 'abc123',
  issuedAt: new Date().toISOString()
})

Constructors (Effect-wrapped)

const message = await Effect.runPromise(Siwe.create({
  domain: 'example.com',
  address: '0x...',
  uri: 'https://example.com',
  chainId: 1,
}))

const parsed = await Effect.runPromise(Siwe.parse(siweString))

Verification (Effect-wrapped)

const isValid = await Effect.runPromise(Siwe.verify(message, signature))
const result = await Effect.runPromise(Siwe.verifyMessage(message, signature, { now: new Date() }))
const hash = await Effect.runPromise(Siwe.getMessageHash(message))

Pure Functions

Siwe.format(message)        // string
Siwe.validate(message)      // ValidationResult
Siwe.generateNonce(16)      // string

Full Example

const authenticate = (siweText: string, signature: Signature) =>
  Effect.gen(function* () {
    const message = yield* Siwe.parse(siweText)
    const validation = Siwe.validate(message)
    if (!validation.success) {
      return yield* Effect.fail(new Error(validation.errors.join(', ')))
    }
    const isValid = yield* Siwe.verify(message, signature)
    if (!isValid) {
      return yield* Effect.fail(new Error('Invalid signature'))
    }
    return message.address
  })

Errors

  • InvalidFieldError — Field has invalid value
  • InvalidNonceLengthError — Nonce too short
  • InvalidSiweMessageError — Message format invalid
  • MissingFieldError — Required field missing
  • SiweParseError — Failed to parse message