ox
Version:
1,294 lines (1,228 loc) • 40.2 kB
text/typescript
import { P256, Secp256k1 } from 'ox'
import { describe, expect, expectTypeOf, test } from 'vitest'
import * as AuthorizationTempo from './AuthorizationTempo.js'
import * as SignatureEnvelope from './SignatureEnvelope.js'
// Use a fixed private key for testing signatures
const testPrivateKey =
'0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' as const
describe('from', () => {
test('default', () => {
{
const authorization = AuthorizationTempo.from({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 1,
nonce: 40n,
})
expectTypeOf(authorization).toEqualTypeOf<{
readonly address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c'
readonly chainId: 1
readonly nonce: 40n
}>()
expectTypeOf(authorization).toExtend<
AuthorizationTempo.AuthorizationTempo<false>
>()
expect(authorization).toMatchInlineSnapshot(
`
{
"address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
"chainId": 1,
"nonce": 40n,
}
`,
)
}
{
const authorization = AuthorizationTempo.from({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 1,
nonce: 40n,
signature: {
signature: {
r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
yParity: 0,
},
type: 'secp256k1' as const,
},
})
expectTypeOf(authorization).toEqualTypeOf<{
readonly address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c'
readonly chainId: 1
readonly nonce: 40n
readonly signature: {
readonly signature: {
readonly r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n
readonly s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n
readonly yParity: 0
}
readonly type: 'secp256k1'
}
}>()
expectTypeOf(authorization).toExtend<
AuthorizationTempo.AuthorizationTempo<true>
>()
expect(authorization).toMatchInlineSnapshot(
`
{
"address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
"chainId": 1,
"nonce": 40n,
"signature": {
"signature": {
"r": 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
"s": 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
"yParity": 0,
},
"type": "secp256k1",
},
}
`,
)
}
})
test('options: signature (secp256k1)', () => {
const authorization = AuthorizationTempo.from({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 1,
nonce: 40n,
})
const signature = Secp256k1.sign({
payload: AuthorizationTempo.getSignPayload(authorization),
privateKey: testPrivateKey,
})
const authorization_signed = AuthorizationTempo.from(authorization, {
signature,
})
expectTypeOf(authorization_signed).toExtend<{
readonly address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c'
readonly chainId: 1
readonly nonce: 40n
}>()
expectTypeOf(authorization_signed).toExtend<
AuthorizationTempo.AuthorizationTempo<true>
>()
expect(authorization_signed).toMatchInlineSnapshot(
`
{
"address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
"chainId": 1,
"nonce": 40n,
"signature": {
"r": 74666311849961653398815470296948700361392062371901161364182304079113687952627n,
"s": 24912990662134805731506157958890440652926649106845286943280690489391727501383n,
"yParity": 1,
},
}
`,
)
})
test('options: signature (secp256k1)', () => {
const authorization = AuthorizationTempo.from({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 1,
nonce: 40n,
})
const signature = Secp256k1.sign({
payload: AuthorizationTempo.getSignPayload(authorization),
privateKey: testPrivateKey,
})
const signatureEnvelope = SignatureEnvelope.from({
signature,
type: 'secp256k1',
})
const authorization_signed = AuthorizationTempo.from(authorization, {
signature: signatureEnvelope,
})
expectTypeOf(authorization_signed).toExtend<{
readonly address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c'
readonly chainId: 1
readonly nonce: 40n
}>()
expectTypeOf(authorization_signed).toExtend<
AuthorizationTempo.AuthorizationTempo<true>
>()
expect(authorization_signed).toMatchInlineSnapshot(
`
{
"address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
"chainId": 1,
"nonce": 40n,
"signature": {
"signature": {
"r": 74666311849961653398815470296948700361392062371901161364182304079113687952627n,
"s": 24912990662134805731506157958890440652926649106845286943280690489391727501383n,
"yParity": 1,
},
"type": "secp256k1",
},
}
`,
)
})
test('options: signature (p256)', () => {
const authorization = AuthorizationTempo.from({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 1,
nonce: 40n,
})
const privateKey = P256.randomPrivateKey()
const publicKey = P256.getPublicKey({ privateKey })
const payload = AuthorizationTempo.getSignPayload(authorization)
const signature = P256.sign({ payload, privateKey })
const signatureEnvelope: SignatureEnvelope.P256 = {
prehash: true,
publicKey,
signature,
type: 'p256',
}
const authorization_signed = AuthorizationTempo.from(authorization, {
signature: signatureEnvelope,
})
expectTypeOf(authorization_signed).toExtend<
AuthorizationTempo.AuthorizationTempo<true>
>()
expect(authorization_signed.signature.type).toBe('p256')
expect(authorization_signed.signature.prehash).toBe(true)
expect(authorization_signed.signature.publicKey).toEqual(publicKey)
})
test('options: signature (webAuthn)', () => {
const authorization = AuthorizationTempo.from({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 1,
nonce: 40n,
})
const signatureEnvelope = SignatureEnvelope.from({
metadata: {
authenticatorData:
'0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000',
clientDataJSON:
'{"type":"webauthn.get","challenge":"","origin":"https://example.com","crossOrigin":false}',
},
publicKey: { prefix: 4, x: 1n, y: 2n },
signature: { r: 3n, s: 4n },
type: 'webAuthn',
})
const authorization_signed = AuthorizationTempo.from(authorization, {
signature: signatureEnvelope,
})
expectTypeOf(authorization_signed).toExtend<
AuthorizationTempo.AuthorizationTempo<true>
>()
expect(authorization_signed.signature.type).toBe('webAuthn')
expect(authorization_signed.signature.metadata).toBeDefined()
expect(authorization_signed.signature.publicKey).toEqual(
signatureEnvelope.publicKey,
)
})
test('behavior: rpc', () => {
{
const authorization = AuthorizationTempo.from({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: '0x1',
nonce: '0x1',
signature: {
r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
yParity: '0x0',
type: 'secp256k1',
},
})
expectTypeOf(
authorization,
).toExtend<AuthorizationTempo.AuthorizationTempo>()
expect(authorization).toMatchInlineSnapshot(
`
{
"address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
"chainId": 1,
"nonce": 1n,
"signature": {
"signature": {
"r": 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
"s": 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
"yParity": 0,
},
"type": "secp256k1",
},
}
`,
)
}
})
})
describe('fromRpc', () => {
test('secp256k1', () => {
expect(
AuthorizationTempo.fromRpc({
address: '0x0000000000000000000000000000000000000000',
chainId: '0x1',
nonce: '0x1',
signature: {
r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
yParity: '0x0',
type: 'secp256k1',
},
}),
).toMatchInlineSnapshot(`
{
"address": "0x0000000000000000000000000000000000000000",
"chainId": 1,
"nonce": 1n,
"signature": {
"signature": {
"r": 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
"s": 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
"yParity": 0,
},
"type": "secp256k1",
},
}
`)
})
test('p256', () => {
const result = AuthorizationTempo.fromRpc({
address: '0x0000000000000000000000000000000000000000',
chainId: '0x1',
nonce: '0x1',
signature: {
preHash: true,
pubKeyX:
'0x0000000000000000000000000000000000000000000000000000000000000001',
pubKeyY:
'0x0000000000000000000000000000000000000000000000000000000000000002',
r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
type: 'p256',
},
})
expect(result.signature.type).toBe('p256')
expect(result.signature).toHaveProperty('prehash', true)
expect(result.signature).toHaveProperty('publicKey')
})
test('webAuthn', () => {
const result = AuthorizationTempo.fromRpc({
address: '0x0000000000000000000000000000000000000000',
chainId: '0x1',
nonce: '0x1',
signature: {
pubKeyX:
'0x0000000000000000000000000000000000000000000000000000000000000001',
pubKeyY:
'0x0000000000000000000000000000000000000000000000000000000000000002',
r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
type: 'webAuthn',
webauthnData:
'0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d976305000000007b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22222c226f726967696e223a2268747470733a2f2f6578616d706c652e636f6d222c2263726f73734f726967696e223a66616c73657d',
},
})
expect(result.signature.type).toBe('webAuthn')
expect(result.signature).toHaveProperty('metadata')
expect(result.signature).toHaveProperty('publicKey')
})
})
describe('fromRpcList', () => {
test('secp256k1', () => {
expect(
AuthorizationTempo.fromRpcList([
{
address: '0x0000000000000000000000000000000000000000',
chainId: '0x1',
nonce: '0x1',
signature: {
r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
yParity: '0x0',
type: 'secp256k1',
},
},
{
address: '0x0000000000000000000000000000000000000000',
chainId: '0x1',
nonce: '0x1',
signature: {
r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
yParity: '0x0',
type: 'secp256k1',
},
},
]),
).toMatchInlineSnapshot(`
[
{
"address": "0x0000000000000000000000000000000000000000",
"chainId": 1,
"nonce": 1n,
"signature": {
"signature": {
"r": 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
"s": 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
"yParity": 0,
},
"type": "secp256k1",
},
},
{
"address": "0x0000000000000000000000000000000000000000",
"chainId": 1,
"nonce": 1n,
"signature": {
"signature": {
"r": 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
"s": 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
"yParity": 0,
},
"type": "secp256k1",
},
},
]
`)
})
test('p256', () => {
expect(
AuthorizationTempo.fromRpcList([
{
address: '0x0000000000000000000000000000000000000000',
chainId: '0x1',
nonce: '0x1',
signature: {
preHash: true,
pubKeyX:
'0x0000000000000000000000000000000000000000000000000000000000000001',
pubKeyY:
'0x0000000000000000000000000000000000000000000000000000000000000002',
r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
type: 'p256',
},
},
{
address: '0x0000000000000000000000000000000000000001',
chainId: '0x2',
nonce: '0x2',
signature: {
preHash: false,
pubKeyX:
'0x0000000000000000000000000000000000000000000000000000000000000003',
pubKeyY:
'0x0000000000000000000000000000000000000000000000000000000000000004',
r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
type: 'p256',
},
},
]),
).toMatchInlineSnapshot(`
[
{
"address": "0x0000000000000000000000000000000000000000",
"chainId": 1,
"nonce": 1n,
"signature": {
"prehash": true,
"publicKey": {
"prefix": 4,
"x": 1n,
"y": 2n,
},
"signature": {
"r": 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
"s": 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
},
"type": "p256",
},
},
{
"address": "0x0000000000000000000000000000000000000001",
"chainId": 2,
"nonce": 2n,
"signature": {
"prehash": false,
"publicKey": {
"prefix": 4,
"x": 3n,
"y": 4n,
},
"signature": {
"r": 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
"s": 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
},
"type": "p256",
},
},
]
`)
})
test('webAuthn', () => {
expect(
AuthorizationTempo.fromRpcList([
{
address: '0x0000000000000000000000000000000000000000',
chainId: '0x1',
nonce: '0x1',
signature: {
pubKeyX:
'0x0000000000000000000000000000000000000000000000000000000000000001',
pubKeyY:
'0x0000000000000000000000000000000000000000000000000000000000000002',
r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
type: 'webAuthn',
webauthnData:
'0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d976305000000007b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22222c226f726967696e223a2268747470733a2f2f6578616d706c652e636f6d222c2263726f73734f726967696e223a66616c73657d',
},
},
{
address: '0x0000000000000000000000000000000000000001',
chainId: '0x2',
nonce: '0x2',
signature: {
pubKeyX:
'0x0000000000000000000000000000000000000000000000000000000000000003',
pubKeyY:
'0x0000000000000000000000000000000000000000000000000000000000000004',
r: '0x1',
s: '0x2',
type: 'webAuthn',
webauthnData:
'0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d976305000000007b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22222c226f726967696e223a2268747470733a2f2f6578616d706c652e636f6d222c2263726f73734f726967696e223a66616c73657d',
},
},
]),
).toMatchInlineSnapshot(`
[
{
"address": "0x0000000000000000000000000000000000000000",
"chainId": 1,
"nonce": 1n,
"signature": {
"metadata": {
"authenticatorData": "0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000",
"clientDataJSON": "{"type":"webauthn.get","challenge":"","origin":"https://example.com","crossOrigin":false}",
},
"publicKey": {
"prefix": 4,
"x": 1n,
"y": 2n,
},
"signature": {
"r": 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
"s": 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
},
"type": "webAuthn",
},
},
{
"address": "0x0000000000000000000000000000000000000001",
"chainId": 2,
"nonce": 2n,
"signature": {
"metadata": {
"authenticatorData": "0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000",
"clientDataJSON": "{"type":"webauthn.get","challenge":"","origin":"https://example.com","crossOrigin":false}",
},
"publicKey": {
"prefix": 4,
"x": 3n,
"y": 4n,
},
"signature": {
"r": 1n,
"s": 2n,
},
"type": "webAuthn",
},
},
]
`)
})
test('mixed signature types', () => {
expect(
AuthorizationTempo.fromRpcList([
{
address: '0x0000000000000000000000000000000000000000',
chainId: '0x1',
nonce: '0x1',
signature: {
r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
yParity: '0x0',
type: 'secp256k1',
},
},
{
address: '0x0000000000000000000000000000000000000001',
chainId: '0x2',
nonce: '0x2',
signature: {
preHash: true,
pubKeyX:
'0x0000000000000000000000000000000000000000000000000000000000000003',
pubKeyY:
'0x0000000000000000000000000000000000000000000000000000000000000004',
r: '0x1',
s: '0x2',
type: 'p256',
},
},
{
address: '0x0000000000000000000000000000000000000002',
chainId: '0x3',
nonce: '0x3',
signature: {
pubKeyX:
'0x0000000000000000000000000000000000000000000000000000000000000005',
pubKeyY:
'0x0000000000000000000000000000000000000000000000000000000000000006',
r: '0x3',
s: '0x4',
type: 'webAuthn',
webauthnData:
'0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d976305000000007b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22222c226f726967696e223a2268747470733a2f2f6578616d706c652e636f6d222c2263726f73734f726967696e223a66616c73657d',
},
},
]),
).toMatchInlineSnapshot(`
[
{
"address": "0x0000000000000000000000000000000000000000",
"chainId": 1,
"nonce": 1n,
"signature": {
"signature": {
"r": 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
"s": 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
"yParity": 0,
},
"type": "secp256k1",
},
},
{
"address": "0x0000000000000000000000000000000000000001",
"chainId": 2,
"nonce": 2n,
"signature": {
"prehash": true,
"publicKey": {
"prefix": 4,
"x": 3n,
"y": 4n,
},
"signature": {
"r": 1n,
"s": 2n,
},
"type": "p256",
},
},
{
"address": "0x0000000000000000000000000000000000000002",
"chainId": 3,
"nonce": 3n,
"signature": {
"metadata": {
"authenticatorData": "0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000",
"clientDataJSON": "{"type":"webauthn.get","challenge":"","origin":"https://example.com","crossOrigin":false}",
},
"publicKey": {
"prefix": 4,
"x": 5n,
"y": 6n,
},
"signature": {
"r": 3n,
"s": 4n,
},
"type": "webAuthn",
},
},
]
`)
})
})
describe('fromTuple', () => {
test('default', () => {
const tuple = [
'0x1',
'0x0000000000000000000000000000000000000000',
'0x3',
] as const satisfies AuthorizationTempo.Tuple
const authorization = AuthorizationTempo.fromTuple(tuple)
expect(authorization).toMatchInlineSnapshot(`
{
"address": "0x0000000000000000000000000000000000000000",
"chainId": 1,
"nonce": 3n,
}
`)
})
test('behavior: zeroish nonce + chainId', () => {
const tuple = [
'0x',
'0x0000000000000000000000000000000000000000',
'0x',
] as const satisfies AuthorizationTempo.Tuple
const authorization = AuthorizationTempo.fromTuple(tuple)
expect(authorization).toMatchInlineSnapshot(`
{
"address": "0x0000000000000000000000000000000000000000",
"chainId": 0,
"nonce": 0n,
}
`)
})
test('behavior: signature (secp256k1)', () => {
const signatureEnvelope = SignatureEnvelope.from({
signature: { r: 1n, s: 2n, yParity: 0 },
type: 'secp256k1',
})
const serialized = SignatureEnvelope.serialize(signatureEnvelope)
const tuple = [
'0x1',
'0x0000000000000000000000000000000000000000',
'0x3',
serialized,
] as const satisfies AuthorizationTempo.Tuple
const authorization = AuthorizationTempo.fromTuple(tuple)
expect(authorization).toMatchInlineSnapshot(`
{
"address": "0x0000000000000000000000000000000000000000",
"chainId": 1,
"nonce": 3n,
"signature": {
"signature": {
"r": 1n,
"s": 2n,
"yParity": 0,
},
"type": "secp256k1",
},
}
`)
})
test('behavior: signature (p256)', () => {
const signatureEnvelope = SignatureEnvelope.from({
prehash: true,
publicKey: { prefix: 4, x: 1n, y: 2n },
signature: { r: 3n, s: 4n },
type: 'p256',
})
const serialized = SignatureEnvelope.serialize(signatureEnvelope)
const tuple = [
'0x1',
'0x0000000000000000000000000000000000000000',
'0x3',
serialized,
] as const satisfies AuthorizationTempo.Tuple
const authorization = AuthorizationTempo.fromTuple(tuple)
expect(authorization.signature?.type).toBe('p256')
})
})
describe('fromTupleList', () => {
test('default', () => {
const tupleList = [
['0x01', '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', '0x28'],
['0x03', '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', '0x14'],
] as const satisfies AuthorizationTempo.TupleList
const authorization = AuthorizationTempo.fromTupleList(tupleList)
expect(authorization).toMatchInlineSnapshot(`
[
{
"address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
"chainId": 1,
"nonce": 40n,
},
{
"address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
"chainId": 3,
"nonce": 20n,
},
]
`)
})
test('behavior: signature', () => {
const signatureEnvelope1 = SignatureEnvelope.from({
signature: { r: 1n, s: 2n, yParity: 0 },
type: 'secp256k1',
})
const signatureEnvelope2 = SignatureEnvelope.from({
signature: { r: 4n, s: 5n, yParity: 0 },
type: 'secp256k1',
})
const authorization = AuthorizationTempo.fromTupleList([
[
'0x05',
'0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
'0x2a',
SignatureEnvelope.serialize(signatureEnvelope1),
],
[
'0x02',
'0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
'0x2b',
SignatureEnvelope.serialize(signatureEnvelope2),
],
])
expect(authorization).toMatchInlineSnapshot(`
[
{
"address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
"chainId": 5,
"nonce": 42n,
"signature": {
"signature": {
"r": 1n,
"s": 2n,
"yParity": 0,
},
"type": "secp256k1",
},
},
{
"address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
"chainId": 2,
"nonce": 43n,
"signature": {
"signature": {
"r": 4n,
"s": 5n,
"yParity": 0,
},
"type": "secp256k1",
},
},
]
`)
})
})
describe('getSignPayload', () => {
test('default', () => {
expect(
AuthorizationTempo.getSignPayload({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 1,
nonce: 40n,
}),
).toMatchInlineSnapshot(
`"0x5919da563810a99caf657d42bd10905adbd28b3b89b8a4577efa471e5e4b3914"`,
)
expect(
AuthorizationTempo.getSignPayload({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 69,
nonce: 420n,
}),
).toMatchInlineSnapshot(
`"0x7bdd120f6437316be99b11232d472bb0209d20d7c564f4dfbad855189e830b15"`,
)
})
})
describe('hash', () => {
test('default', () => {
expect(
AuthorizationTempo.hash({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 1,
nonce: 40n,
}),
).toMatchInlineSnapshot(
`"0x5919da563810a99caf657d42bd10905adbd28b3b89b8a4577efa471e5e4b3914"`,
)
expect(
AuthorizationTempo.hash({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 69,
nonce: 420n,
}),
).toMatchInlineSnapshot(
`"0x7bdd120f6437316be99b11232d472bb0209d20d7c564f4dfbad855189e830b15"`,
)
})
test('options: presign equals getSignPayload', () => {
const authorization = {
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 1,
nonce: 40n,
} as const
const payload = AuthorizationTempo.getSignPayload(authorization)
const hash_presign = AuthorizationTempo.hash(authorization, {
presign: true,
})
expect(hash_presign).toEqual(payload)
})
})
describe('toRpc', () => {
test('secp256k1', () => {
expect(
AuthorizationTempo.toRpc({
address: '0x0000000000000000000000000000000000000000',
chainId: 1,
nonce: 1n,
signature: {
signature: {
r: 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
s: 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
yParity: 0,
},
type: 'secp256k1',
},
}),
).toMatchInlineSnapshot(`
{
"address": "0x0000000000000000000000000000000000000000",
"chainId": "0x1",
"nonce": "0x1",
"signature": {
"r": "0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d",
"s": "0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540",
"type": "secp256k1",
"yParity": "0x0",
},
}
`)
})
test('p256', () => {
const result = AuthorizationTempo.toRpc({
address: '0x0000000000000000000000000000000000000000',
chainId: 1,
nonce: 1n,
signature: {
prehash: true,
publicKey: { prefix: 4, x: 1n, y: 2n },
signature: {
r: 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
s: 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
},
type: 'p256',
},
})
expect(result.signature.type).toBe('p256')
})
test('webAuthn', () => {
const result = AuthorizationTempo.toRpc({
address: '0x0000000000000000000000000000000000000000',
chainId: 1,
nonce: 1n,
signature: {
metadata: {
authenticatorData: '0x1234',
clientDataJSON: '0x5678',
},
publicKey: { prefix: 4, x: 1n, y: 2n },
signature: {
r: 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
s: 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
},
type: 'webAuthn',
},
})
expect(result.signature.type).toBe('webAuthn')
})
})
describe('toRpcList', () => {
test('default', () => {
expect(
AuthorizationTempo.toRpcList([
{
address: '0x0000000000000000000000000000000000000000',
chainId: 1,
nonce: 1n,
signature: {
signature: {
r: 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
s: 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
yParity: 0,
},
type: 'secp256k1',
},
},
]),
).toMatchInlineSnapshot(`
[
{
"address": "0x0000000000000000000000000000000000000000",
"chainId": "0x1",
"nonce": "0x1",
"signature": {
"r": "0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d",
"s": "0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540",
"type": "secp256k1",
"yParity": "0x0",
},
},
]
`)
})
})
describe('toTuple', () => {
test('default', () => {
{
const authorization = AuthorizationTempo.from({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 1,
nonce: 40n,
})
const tuple = AuthorizationTempo.toTuple(authorization)
expect(tuple).toMatchInlineSnapshot(`
[
"0x1",
"0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
"0x28",
]
`)
}
{
const signatureEnvelope: SignatureEnvelope.Secp256k1 = {
signature: { r: 1n, s: 2n, yParity: 0 },
type: 'secp256k1',
}
const authorization = AuthorizationTempo.from({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 1,
nonce: 40n,
signature: signatureEnvelope,
})
const tuple = AuthorizationTempo.toTuple(authorization)
expect(tuple).toMatchInlineSnapshot(`
[
"0x1",
"0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
"0x28",
"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021b",
]
`)
}
{
const authorization = AuthorizationTempo.from({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 0,
nonce: 0n,
})
const tuple = AuthorizationTempo.toTuple(authorization)
expect(tuple).toMatchInlineSnapshot(`
[
"0x",
"0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
"0x",
]
`)
}
})
})
describe('toTupleList', () => {
test('default', () => {
{
const tuple = AuthorizationTempo.toTupleList([])
expect(tuple).toMatchInlineSnapshot('[]')
}
{
const authorization_1 = AuthorizationTempo.from({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 1,
nonce: 40n,
})
const authorization_2 = AuthorizationTempo.from({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 3,
nonce: 20n,
})
const tuple = AuthorizationTempo.toTupleList([
authorization_1,
authorization_2,
])
expect(tuple).toMatchInlineSnapshot(`
[
[
"0x1",
"0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
"0x28",
],
[
"0x3",
"0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
"0x14",
],
]
`)
}
{
const signatureEnvelope1 = SignatureEnvelope.from({
signature: { r: 1n, s: 2n, yParity: 0 },
type: 'secp256k1',
})
const signatureEnvelope2 = SignatureEnvelope.from({
signature: { r: 4n, s: 5n, yParity: 0 },
type: 'secp256k1',
})
const authorization_3 = AuthorizationTempo.from({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 5,
nonce: 42n,
signature: signatureEnvelope1,
})
const authorization_4 = AuthorizationTempo.from({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 2,
nonce: 43n,
signature: signatureEnvelope2,
})
const tuple = AuthorizationTempo.toTupleList([
authorization_3,
authorization_4,
])
expect(tuple).toMatchInlineSnapshot(`
[
[
"0x5",
"0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
"0x2a",
"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021b",
],
[
"0x2",
"0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
"0x2b",
"0x000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000051b",
],
]
`)
}
})
test('behavior: undefined input returns empty', () => {
const tuple = AuthorizationTempo.toTupleList()
expect(tuple).toMatchInlineSnapshot('[]')
})
})
describe('signature type interoperability', () => {
test('secp256k1 signature round trip', () => {
const authorization = AuthorizationTempo.from({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 1,
nonce: 40n,
})
const signature = Secp256k1.sign({
payload: AuthorizationTempo.getSignPayload(authorization),
privateKey: testPrivateKey,
})
const signatureEnvelope = SignatureEnvelope.from({
signature,
type: 'secp256k1',
})
const signed = AuthorizationTempo.from(authorization, {
signature: signatureEnvelope,
})
const rpc = AuthorizationTempo.toRpc(signed)
const restored = AuthorizationTempo.fromRpc(rpc)
expect(restored).toEqual(signed)
})
test('p256 signature round trip', () => {
const authorization = AuthorizationTempo.from({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 1,
nonce: 40n,
})
const privateKey = P256.randomPrivateKey()
const publicKey = P256.getPublicKey({ privateKey })
const payload = AuthorizationTempo.getSignPayload(authorization)
const signature = P256.sign({ payload, privateKey })
const signatureEnvelope = SignatureEnvelope.from({
prehash: true,
publicKey,
signature,
type: 'p256',
})
const signed = AuthorizationTempo.from(authorization, {
signature: signatureEnvelope,
})
const rpc = AuthorizationTempo.toRpc(signed)
const restored = AuthorizationTempo.fromRpc(rpc)
expect(restored.signature.type).toBe('p256')
expect(restored.address).toEqual(signed.address)
expect(restored.chainId).toEqual(signed.chainId)
expect(restored.nonce).toEqual(signed.nonce)
expect(restored.signature.type).toEqual(signed.signature.type)
expect(restored.signature.prehash).toEqual(signed.signature.prehash)
expect(restored.signature.publicKey).toEqual(signed.signature.publicKey)
expect(restored.signature.signature?.r).toEqual(
signed.signature.signature?.r,
)
expect(restored.signature.signature?.s).toEqual(
signed.signature.signature?.s,
)
})
test('webAuthn signature round trip', () => {
const authorization = AuthorizationTempo.from({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 1,
nonce: 40n,
})
const signatureEnvelope = SignatureEnvelope.from({
metadata: {
authenticatorData:
'0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000',
clientDataJSON:
'{"type":"webauthn.get","challenge":"","origin":"https://example.com","crossOrigin":false}',
},
publicKey: { prefix: 4, x: 1n, y: 2n },
signature: {
r: 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
s: 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
},
type: 'webAuthn',
})
const signed = AuthorizationTempo.from(authorization, {
signature: signatureEnvelope,
})
const rpc = AuthorizationTempo.toRpc(signed)
const restored = AuthorizationTempo.fromRpc(rpc)
expect(restored.signature.type).toBe('webAuthn')
expect(restored.address).toEqual(signed.address)
expect(restored.chainId).toEqual(signed.chainId)
expect(restored.nonce).toEqual(signed.nonce)
expect(restored.signature.type).toEqual(signed.signature.type)
expect(restored.signature.metadata).toEqual(signed.signature.metadata)
expect(restored.signature.publicKey).toEqual(signed.signature.publicKey)
expect(restored.signature.signature?.r).toEqual(
signed.signature.signature?.r,
)
expect(restored.signature.signature?.s).toEqual(
signed.signature.signature?.s,
)
})
test('tuple serialization preserves signature type', () => {
const signatureEnvelope = SignatureEnvelope.from({
prehash: true,
publicKey: { prefix: 4, x: 1n, y: 2n },
signature: { r: 3n, s: 4n },
type: 'p256',
})
const authorization = AuthorizationTempo.from({
address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
chainId: 1,
nonce: 40n,
signature: signatureEnvelope,
})
const tuple = AuthorizationTempo.toTuple(authorization)
const restored = AuthorizationTempo.fromTuple(tuple)
expect(restored.signature?.type).toBe('p256')
})
})
test('exports', () => {
expect(Object.keys(AuthorizationTempo)).toMatchInlineSnapshot(`
[
"from",
"fromRpc",
"fromRpcList",
"fromTuple",
"fromTupleList",
"getSignPayload",
"hash",
"toRpc",
"toRpcList",
"toTuple",
"toTupleList",
]
`)
})