UNPKG

ox

Version:

Ethereum Standard Library

651 lines (621 loc) 19.3 kB
import { Authorization, type Hex, Secp256k1 } from 'ox' import { describe, expect, expectTypeOf, test } from 'vp/test' import { accounts } from '../../../test/constants/accounts.js' describe('from', () => { test('default', () => { { const authorization = Authorization.from({ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', chainId: 1, nonce: 40n, }) expectTypeOf(authorization).toEqualTypeOf<{ readonly address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c' readonly chainId: 1 readonly nonce: 40n }>() expectTypeOf(authorization).toMatchTypeOf< Authorization.Authorization<false> >() expect(authorization).toMatchInlineSnapshot( ` { "address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c", "chainId": 1, "nonce": 40n, } `, ) } { const authorization = Authorization.from({ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', chainId: 1, nonce: 40n, r: '0x6e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf', s: '0x4a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db8', yParity: 0, }) expectTypeOf(authorization).toEqualTypeOf<{ readonly address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c' readonly chainId: 1 readonly nonce: 40n readonly r: '0x6e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf' readonly s: '0x4a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db8' readonly yParity: 0 }>() expectTypeOf(authorization).toMatchTypeOf< Authorization.Authorization<true> >() expect(authorization).toMatchInlineSnapshot( ` { "address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c", "chainId": 1, "nonce": 40n, "r": "0x6e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf", "s": "0x4a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db8", "yParity": 0, } `, ) } }) test('options: signature', () => { const authorization = Authorization.from({ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', chainId: 1, nonce: 40n, }) const signature = Secp256k1.sign({ payload: Authorization.getSignPayload(authorization), privateKey: accounts[0].privateKey, }) const authorization_signed = Authorization.from(authorization, { signature, }) expectTypeOf(authorization_signed).toEqualTypeOf<{ readonly address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c' readonly chainId: 1 readonly nonce: 40n readonly r: Hex.Hex readonly s: Hex.Hex readonly yParity: number }>() expectTypeOf(authorization_signed).toMatchTypeOf< Authorization.Authorization<true> >() expect(authorization_signed).toMatchInlineSnapshot( ` { "address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c", "chainId": 1, "nonce": 40n, "r": "0xa513a287a156a99f2be4023466d401589e33add75c057e5fd376d11ed8946cf3", "s": "0x371440c5f5c845ae5260bffccf9e28307b9204216faeaa0e27a6608bcdd7e047", "yParity": 1, } `, ) }) test('behavior: rpc', () => { { const authorization = Authorization.from({ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', chainId: '0x1', nonce: '0x1', r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d', s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540', yParity: '0x0', }) expectTypeOf(authorization).toMatchTypeOf<Authorization.Authorization>() expect(authorization).toMatchInlineSnapshot( ` { "address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c", "chainId": 1, "nonce": 1n, "r": "0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d", "s": "0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540", "yParity": 0, } `, ) } }) }) describe('fromRpc', () => { test('default', () => { expect( Authorization.fromRpc({ address: '0x0000000000000000000000000000000000000000', chainId: '0x1', nonce: '0x1', r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d', s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540', yParity: '0x0', }), ).toMatchInlineSnapshot(` { "address": "0x0000000000000000000000000000000000000000", "chainId": 1, "nonce": 1n, "r": "0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d", "s": "0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540", "yParity": 0, } `) }) }) describe('fromRpcList', () => { test('default', () => { expect( Authorization.fromRpcList([ { address: '0x0000000000000000000000000000000000000000', chainId: '0x1', nonce: '0x1', r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d', s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540', yParity: '0x0', }, { address: '0x0000000000000000000000000000000000000000', chainId: '0x1', nonce: '0x1', r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d', s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540', yParity: '0x0', }, ]), ).toMatchInlineSnapshot(` [ { "address": "0x0000000000000000000000000000000000000000", "chainId": 1, "nonce": 1n, "r": "0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d", "s": "0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540", "yParity": 0, }, { "address": "0x0000000000000000000000000000000000000000", "chainId": 1, "nonce": 1n, "r": "0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d", "s": "0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540", "yParity": 0, }, ] `) }) }) describe('fromTuple', () => { test('default', () => { const tuple = [ '0x1', '0x0000000000000000000000000000000000000000', '0x3', ] as const satisfies Authorization.Tuple const authorization = Authorization.fromTuple(tuple) expect(authorization).toMatchInlineSnapshot(` { "address": "0x0000000000000000000000000000000000000000", "chainId": 1, "nonce": 3n, } `) }) test('behavior: zeroish nonce + chainId', () => { const tuple = [ '0x', '0x0000000000000000000000000000000000000000', '0x', ] as const satisfies Authorization.Tuple const authorization = Authorization.fromTuple(tuple) expect(authorization).toMatchInlineSnapshot(` { "address": "0x0000000000000000000000000000000000000000", "chainId": 0, "nonce": 0n, } `) }) test('behavior: signature', () => { const tuple = [ '0x1', '0x0000000000000000000000000000000000000000', '0x3', '0x', '0x01', '0x02', ] as const satisfies Authorization.Tuple const authorization = Authorization.fromTuple(tuple) expect(authorization).toMatchInlineSnapshot(` { "address": "0x0000000000000000000000000000000000000000", "chainId": 1, "nonce": 3n, "r": "0x0000000000000000000000000000000000000000000000000000000000000001", "s": "0x0000000000000000000000000000000000000000000000000000000000000002", "yParity": 0, } `) }) }) describe('fromTupleList', () => { test('default', () => { const tupleList = [ ['0x01', '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', '0x28'], ['0x03', '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', '0x14'], ] as const satisfies Authorization.TupleList const authorization = Authorization.fromTupleList(tupleList) expectTypeOf(authorization).toMatchTypeOf<Authorization.List<false>>() expect(authorization).toMatchInlineSnapshot(` [ { "address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c", "chainId": 1, "nonce": 40n, }, { "address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c", "chainId": 3, "nonce": 20n, }, ] `) }) test('behavior: signature', () => { const tupleList = [ [ '0x05', '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', '0x2a', '0x', '0x01', '0x02', ], [ '0x02', '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', '0x2b', '0x', '0x04', '0x05', ], ] as const satisfies Authorization.TupleList const authorization = Authorization.fromTupleList(tupleList) expect(authorization).toMatchInlineSnapshot(` [ { "address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c", "chainId": 5, "nonce": 42n, "r": "0x0000000000000000000000000000000000000000000000000000000000000001", "s": "0x0000000000000000000000000000000000000000000000000000000000000002", "yParity": 0, }, { "address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c", "chainId": 2, "nonce": 43n, "r": "0x0000000000000000000000000000000000000000000000000000000000000004", "s": "0x0000000000000000000000000000000000000000000000000000000000000005", "yParity": 0, }, ] `) }) }) describe('getSignPayload', () => { test('default', () => { expect( Authorization.getSignPayload({ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', chainId: 1, nonce: 40n, }), ).toMatchInlineSnapshot( `"0x5919da563810a99caf657d42bd10905adbd28b3b89b8a4577efa471e5e4b3914"`, ) expect( Authorization.getSignPayload({ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', chainId: 69, nonce: 420n, }), ).toMatchInlineSnapshot( `"0x7bdd120f6437316be99b11232d472bb0209d20d7c564f4dfbad855189e830b15"`, ) }) }) describe('hash', () => { test('default', () => { expect( Authorization.hash({ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', chainId: 1, nonce: 40n, }), ).toMatchInlineSnapshot( `"0x5919da563810a99caf657d42bd10905adbd28b3b89b8a4577efa471e5e4b3914"`, ) expect( Authorization.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 = Authorization.getSignPayload(authorization) const hash_presign = Authorization.hash(authorization, { presign: true }) expect(hash_presign).toEqual(payload) }) test('behavior: signed vs presign', () => { const authorization = Authorization.from({ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', chainId: 1, nonce: 40n, }) const signature = Secp256k1.sign({ payload: Authorization.getSignPayload(authorization), privateKey: accounts[0].privateKey, }) const signed = Authorization.from(authorization, { signature }) const hash_default = Authorization.hash(signed) const hash_presign = Authorization.hash(signed, { presign: true }) expect(hash_default).not.toEqual(hash_presign) expect(hash_presign).toEqual(Authorization.getSignPayload(authorization)) expect( Secp256k1.recoverAddress({ payload: Authorization.hash(authorization, { presign: true }), signature, }), ).toEqual(accounts[0].address) }) }) describe('toRpc', () => { test('default', () => { expect( Authorization.toRpc({ address: '0x0000000000000000000000000000000000000000', chainId: 1, nonce: 1n, r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d', s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540', yParity: 0, }), ).toMatchInlineSnapshot(` { "address": "0x0000000000000000000000000000000000000000", "chainId": "0x1", "nonce": "0x1", "r": "0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d", "s": "0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540", "yParity": "0x0", } `) }) test('numberish inputs', () => { const fromBigint = Authorization.toRpc({ address: '0x0000000000000000000000000000000000000000', chainId: 1, nonce: 1n, r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d', s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540', yParity: 0, }) const fromNumber = Authorization.toRpc({ address: '0x0000000000000000000000000000000000000000', chainId: 1, nonce: 1, r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d', s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540', yParity: 0, }) const fromHex = Authorization.toRpc({ address: '0x0000000000000000000000000000000000000000', chainId: '0x1', nonce: '0x1', r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d', s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540', yParity: 0, }) expect(fromBigint).toEqual(fromNumber) expect(fromBigint).toEqual(fromHex) }) }) describe('toRpcList', () => { test('default', () => { expect( Authorization.toRpcList([ { address: '0x0000000000000000000000000000000000000000', chainId: 1, nonce: 1n, r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d', s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540', yParity: 0, }, ]), ).toMatchInlineSnapshot(` [ { "address": "0x0000000000000000000000000000000000000000", "chainId": "0x1", "nonce": "0x1", "r": "0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d", "s": "0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540", "yParity": "0x0", }, ] `) }) }) describe('toTuple', () => { test('default', () => { { const authorization = Authorization.from({ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', chainId: 1, nonce: 40n, }) const tuple = Authorization.toTuple(authorization) expect(tuple).toMatchInlineSnapshot(` [ "0x1", "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c", "0x28", ] `) } { const authorization = Authorization.from({ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', chainId: 1, nonce: 40n, r: '0x0000000000000000000000000000000000000000000000000000000000000001', s: '0x0000000000000000000000000000000000000000000000000000000000000002', yParity: 0, }) const tuple = Authorization.toTuple(authorization) expect(tuple).toMatchInlineSnapshot(` [ "0x1", "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c", "0x28", "0x", "0x1", "0x2", ] `) } { const authorization = Authorization.from({ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', chainId: 0, nonce: 0n, }) const tuple = Authorization.toTuple(authorization) expect(tuple).toMatchInlineSnapshot(` [ "0x", "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c", "0x", ] `) } }) }) describe('toTupleList', () => { test('default', () => { { const tuple = Authorization.toTupleList([]) expect(tuple).toMatchInlineSnapshot('[]') } { const authorization_1 = Authorization.from({ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', chainId: 1, nonce: 40n, }) const authorization_2 = Authorization.from({ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', chainId: 3, nonce: 20n, }) const tuple = Authorization.toTupleList([ authorization_1, authorization_2, ]) expect(tuple).toMatchInlineSnapshot(` [ [ "0x1", "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c", "0x28", ], [ "0x3", "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c", "0x14", ], ] `) } { const authorization_3 = Authorization.from({ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', chainId: 5, nonce: 42n, r: '0x0000000000000000000000000000000000000000000000000000000000000001', s: '0x0000000000000000000000000000000000000000000000000000000000000002', yParity: 0, }) const authorization_4 = Authorization.from({ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', chainId: 2, nonce: 43n, r: '0x0000000000000000000000000000000000000000000000000000000000000004', s: '0x0000000000000000000000000000000000000000000000000000000000000005', yParity: 0, }) const tuple = Authorization.toTupleList([ authorization_3, authorization_4, ]) expect(tuple).toMatchInlineSnapshot(` [ [ "0x5", "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c", "0x2a", "0x", "0x1", "0x2", ], [ "0x2", "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c", "0x2b", "0x", "0x4", "0x5", ], ] `) } }) test('behavior: undefined input returns empty', () => { // Explicitly call without an argument to exercise optional parameter path. const tuple = Authorization.toTupleList() expect(tuple).toMatchInlineSnapshot('[]') }) }) test('exports', () => { expect(Object.keys(Authorization)).toMatchInlineSnapshot(` [ "from", "fromRpc", "fromRpcList", "fromTuple", "fromTupleList", "getSignPayload", "hash", "toRpc", "toRpcList", "toTuple", "toTupleList", ] `) })