Files
hanzo.ai/e2e/unit/wallet.spec.ts
zeekay ac2da21e5f sign-in: wallet and phone, and a person claims a wallet's account
/login and /signup draw "Continue with wallet" and "Continue with phone"
after Google and GitHub, each only where IAM's methods say it is on.

Wallet: where IAM signs a wallet in (@hanzo/iam 0.21.37 `wallet`) and the
browser injects an EIP-1193 wallet; the press is loginWithWallet (IAM's
challenge, personal_sign of its EIP-4361 text, IAM's verify) and ends as a
password's sign-in ends. A wallet IAM has not seen is made an account in an
org of its own, with no email.

Phone: where IAM says it sends codes (`code`) and has answered. The number
is read in its country with the SMS consent ticked, then IAM's code flow.
IAM's address lookup answers an email address only, so a number is texted as
any is and the account that holds it is signed in by the code.

Settings -> General -> Sign in another way adds an email or a phone to the
signed-in account through IAM's own proof (addAddress, PUT /v1/iam/address),
drawn only where IAM's methods say `address`. Same account, org, keys and
balance; nothing is created, so nothing earns twice.

Gates: wallet.spec (a throwaway secp256k1 key behind an injected provider),
phone.spec, address.spec. login.spec expects the phone after the providers.
2026-10-26 16:47:32 -07:00

40 lines
1.7 KiB
TypeScript

import { test, expect } from '@playwright/test'
import { declined, injected, wallets } from '../../lib/auth/wallet'
test('a wallet is offered only where the browser injects one that takes requests', () => {
expect(injected({ ethereum: { request: () => Promise.resolve([]) } })).toBe(true)
expect(injected({})).toBe(false)
expect(injected({ ethereum: {} })).toBe(false)
expect(injected({ ethereum: { request: 'eth_requestAccounts' } })).toBe(false)
expect(injected(undefined)).toBe(false)
})
test('the person saying no in the wallet is EIP-1193 4001, and nothing else is', () => {
expect(declined({ code: 4001, message: 'User rejected the request.' })).toBe(true)
expect(declined(Object.assign(new Error('MetaMask: User denied message signature.'), { code: 4001 }))).toBe(true)
expect(declined({ code: -32603, message: 'Internal error' })).toBe(false)
expect(declined(new Error('web3: verification failed: bad-signature'))).toBe(false)
expect(declined(null)).toBe(false)
expect(declined('4001')).toBe(false)
})
test('the wallets claim is read in IAM order, and nothing that is not a chain and an address', () => {
const claims = {
wallets: [
{ chain: 'evm', address: '0x2c7536e3605d9c16a7a3d7b1898e529396a65c23' },
{ chain: 'solana', address: '7EqQdEULxWcraVx3mXKFjc84LhCkMGZCkRuDpvcMwJeK' },
{ chain: 'evm' },
{ chain: '', address: '0x00' },
null,
'evm:0x00',
],
}
expect(wallets(claims)).toEqual([
{ chain: 'evm', address: '0x2c7536e3605d9c16a7a3d7b1898e529396a65c23' },
{ chain: 'solana', address: '7EqQdEULxWcraVx3mXKFjc84LhCkMGZCkRuDpvcMwJeK' },
])
expect(wallets({ wallets: 'evm' })).toEqual([])
expect(wallets({})).toEqual([])
expect(wallets(null)).toEqual([])
})