UNPKG

accounts

Version:

Tempo Accounts SDK

219 lines (183 loc) 6.41 kB
import { tempoLocalnet } from 'viem/chains' import { WebCryptoP256 } from 'viem/tempo' import { describe, expect, test } from 'vp/test' import { accounts, privateKeys } from '../../test/config.js' import * as Account from './Account.js' import * as Store from './Store.js' describe('hydrate', () => { test('default: returns json-rpc account when sign is false', () => { const result = Account.hydrate({ address: accounts[0].address }) expect(result).toMatchInlineSnapshot(` { "address": "${accounts[0].address}", "type": "json-rpc", } `) }) test('behavior: hydrates secp256k1 account', () => { const result = Account.hydrate( { address: accounts[0].address, keyType: 'secp256k1', privateKey: privateKeys[0], }, { signable: true }, ) expect(result.address).toMatchInlineSnapshot(`"${accounts[0].address}"`) expect(result.type).toMatchInlineSnapshot(`"local"`) expect(typeof result.sign).toMatchInlineSnapshot(`"function"`) }) test('behavior: hydrates p256 account', () => { const result = Account.hydrate( { address: accounts[0].address, keyType: 'p256', privateKey: privateKeys[0], }, { signable: true }, ) expect(result.type).toMatchInlineSnapshot(`"local"`) expect(typeof result.sign).toMatchInlineSnapshot(`"function"`) }) test('behavior: hydrates webCrypto account', async () => { const result = Account.hydrate( { address: accounts[0].address, keyType: 'webCrypto', keyPair: await WebCryptoP256.createKeyPair(), }, { signable: true }, ) expect(result.type).toMatchInlineSnapshot(`"local"`) expect(typeof result.sign).toMatchInlineSnapshot(`"function"`) }) test('behavior: hydrates webAuthn_headless account', () => { const result = Account.hydrate( { address: accounts[0].address, keyType: 'webAuthn_headless', privateKey: privateKeys[0], rpId: 'example.com', origin: 'https://example.com', }, { signable: true }, ) expect(result.type).toMatchInlineSnapshot(`"local"`) expect(typeof result.sign).toMatchInlineSnapshot(`"function"`) }) test('error: throws when sign is true but no sign data', () => { expect(() => Account.hydrate({ address: accounts[0].address }, { signable: true }), ).toThrowErrorMatchingInlineSnapshot( `[Provider.UnauthorizedError: Account "${accounts[0].address}" cannot sign.]`, ) }) }) describe('find', () => { function setup( storeAccounts: readonly Account.Store[] = [], accessKeys: readonly Store.AccessKey[] = [], ) { const store = Store.create({ chainId: tempoLocalnet.id }) store.setState({ accounts: storeAccounts, accessKeys, activeAccount: 0 }) return store } test('default: resolves active account', () => { const store = setup([ { address: accounts[0].address, keyType: 'secp256k1', privateKey: privateKeys[0], }, ]) const result = Account.find({ store }) expect(result.address).toMatchInlineSnapshot(`"${accounts[0].address}"`) expect(result.type).toMatchInlineSnapshot(`"json-rpc"`) }) test('behavior: resolves by address', () => { const store = setup([ { address: accounts[0].address, keyType: 'secp256k1', privateKey: privateKeys[0], }, { address: accounts[1].address, keyType: 'secp256k1', privateKey: privateKeys[1], }, ]) const result = Account.find({ address: accounts[1].address, store }) expect(result.address).toMatchInlineSnapshot(`"${accounts[1].address}"`) }) test('behavior: resolves signable account', () => { const store = setup([ { address: accounts[0].address, keyType: 'secp256k1', privateKey: privateKeys[0], }, ]) const result = Account.find({ signable: true, store }) expect(result.type).toMatchInlineSnapshot(`"local"`) expect(typeof result.sign).toMatchInlineSnapshot(`"function"`) }) test('behavior: prefers access key over root account', async () => { const keyPair = await WebCryptoP256.createKeyPair() const store = setup( [{ address: accounts[0].address, keyType: 'secp256k1', privateKey: privateKeys[0] }], [ { address: '0x0000000000000000000000000000000000000099', access: accounts[0].address, chainId: tempoLocalnet.id, keyType: 'webCrypto', keyPair, }, ], ) const result = Account.find({ chainId: tempoLocalnet.id, store, signable: true }) expect(result.source).toMatchInlineSnapshot(`"accessKey"`) }) test('behavior: accessKey false skips access key', async () => { const keyPair = await WebCryptoP256.createKeyPair() const store = setup( [{ address: accounts[0].address, keyType: 'secp256k1', privateKey: privateKeys[0] }], [ { address: '0x0000000000000000000000000000000000000099', access: accounts[0].address, chainId: tempoLocalnet.id, keyType: 'webCrypto', keyPair, }, ], ) const result = Account.find({ accessKey: false, signable: true, store }) expect(result.address).toMatchInlineSnapshot(`"${accounts[0].address}"`) expect(result.source).not.toBe('accessKey') }) test('behavior: falls back to root when no access key exists', () => { const store = setup( [{ address: accounts[0].address, keyType: 'secp256k1', privateKey: privateKeys[0] }], [], ) const result = Account.find({ signable: true, store }) expect(result.address).toMatchInlineSnapshot(`"${accounts[0].address}"`) expect(result.type).toMatchInlineSnapshot(`"local"`) }) test('error: throws when address not found', () => { const store = setup([]) expect(() => Account.find({ address: accounts[0].address, store }), ).toThrowErrorMatchingInlineSnapshot( `[Provider.UnauthorizedError: Account "${accounts[0].address}" not found.]`, ) }) test('error: throws when no active account', () => { const store = setup([]) expect(() => Account.find({ store })).toThrowErrorMatchingInlineSnapshot( `[Provider.DisconnectedError: No active account.]`, ) }) })