Skip to content

Commit

Permalink
feat: add parseEip712Transaction util function (#2948)
Browse files Browse the repository at this point in the history
* fix: add `parseEip712Transaction` util function

* fix(sites,zksync): add `parseEip712Transaction` util function

---------

Co-authored-by: danijelTxFusion <[email protected]>
  • Loading branch information
nikola-bozin-txfusion and danijelTxFusion authored Nov 17, 2024
1 parent c030b22 commit dbd72a4
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/eleven-socks-reflect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"viem": patch
---

Added `parseEip712Transaction` util function in ZKsync extension.
43 changes: 43 additions & 0 deletions site/pages/zksync/utilities/parseEip712Transaction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
description: Parse EIP712 transaction.
---

# parseEip712Transaction

Parses a serialized EIP712 transaction.

## Import

```ts
import { parseEip712Transaction } from 'viem/zksync'
```

## Usage

```ts
import { parseEip712Transaction } from 'viem/zksync'

const serializedTransaction =
'0x71f87f8080808094a61464658afeaf65cccaafd3a512b69a83b77618830f42408001a073a20167b8d23b610b058c05368174495adf7da3a4ed4a57eb6dbdeb1fafc24aa02f87530d663a0d061f69bb564d2c6fb46ae5ae776bbd4bd2a2a4478b9cd1b42a82010e9436615cf349d7f6344891b1e7ca7c72883f5dc04982c350c080c0'
const transaction = parseEip712Transaction(serializedTransaction)
```

## Returns

`ZksyncTransactionSerializableEIP712`

The ZKsync EIP712 transaction.

## Parameters

### tx

- **Type:** [`Hex`](/docs/glossary/types#hex)

The serialized EIP712 transaction.

```ts
const serializedTransaction =
'0x71f87f8080808094a61464658afeaf65cccaafd3a512b69a83b77618830f42408001a073a20167b8d23b610b058c05368174495adf7da3a4ed4a57eb6dbdeb1fafc24aa02f87530d663a0d061f69bb564d2c6fb46ae5ae776bbd4bd2a2a4478b9cd1b42a82010e9436615cf349d7f6344891b1e7ca7c72883f5dc04982c350c080c0'
const transaction = parseEip712Transaction(serializedTransaction)
```
4 changes: 4 additions & 0 deletions site/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1757,6 +1757,10 @@ export const sidebar = {
},
],
},
{
text: 'parseEip712Transaction',
link: '/zksync/utilities/parseEip712Transaction',
},
],
},
],
Expand Down
1 change: 1 addition & 0 deletions src/zksync/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,3 +281,4 @@ export {
type GetGeneralPaymasterInputReturnType,
getGeneralPaymasterInput,
} from './utils/paymaster/getGeneralPaymasterInput.js'
export { parseEip712Transaction } from './utils/parseEip712Transaction.js'
68 changes: 68 additions & 0 deletions src/zksync/utils/parseEip712Transaction.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { expect, test } from 'vitest'
import { parseEip712Transaction } from './parseEip712Transaction.js'

test('default', () => {
const serializedTransaction =
'0x71f87f8080808094a61464658afeaf65cccaafd3a512b69a83b77618830f42408001a073a20167b8d23b610b058c05368174495adf7da3a4ed4a57eb6dbdeb1fafc24aa02f87530d663a0d061f69bb564d2c6fb46ae5ae776bbd4bd2a2a4478b9cd1b42a82010e9436615cf349d7f6344891b1e7ca7c72883f5dc04982c350c080c0'
const transaction = parseEip712Transaction(serializedTransaction)
expect(transaction).toEqual({
type: 'eip712',
nonce: 0,
maxPriorityFeePerGas: 0n,
maxFeePerGas: 0n,
gas: 0n,
to: '0xa61464658afeaf65cccaafd3a512b69a83b77618',
value: 1000000n,
data: '0x',
chainId: 270,
from: '0x36615cf349d7f6344891b1e7ca7c72883f5dc049',
v: 1n,
r: '0x73a20167b8d23b610b058c05368174495adf7da3a4ed4a57eb6dbdeb1fafc24a',
s: '0x2f87530d663a0d061f69bb564d2c6fb46ae5ae776bbd4bd2a2a4478b9cd1b42a',
gasPerPubdata: 50000n,
factoryDeps: [],
customSignature: '0x',
paymaster: undefined,
paymasterInput: undefined,
})
})

test('with paymaster', async () => {
const serializedTransaction =
'0x71f8c880808080808000820144808082014494000000000000000000000000000000000000000082c350c0b841bb509f381d29a038bd2f700bd6a1f1138edfd7a3cf7234c13a03b01a023a30aa53e6bd5e6a50fdcdcf74587c9395b8a314690abbc85aadab5ebcb7678994eacf1bf85b94fd9ae5ebb0f6656f4b77a0e99dcbc5138d54b0bab8448c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000'

const transaction = parseEip712Transaction(serializedTransaction)
expect(transaction).toEqual({
type: 'eip712',
nonce: 0,
maxPriorityFeePerGas: 0n,
maxFeePerGas: 0n,
gas: 0n,
to: '0x',
value: 0n,
data: '0x00',
chainId: 324,
from: '0x0000000000000000000000000000000000000000',
v: 324n,
r: '0x',
s: '0x',
gasPerPubdata: 50000n,
factoryDeps: [],
customSignature:
'0xbb509f381d29a038bd2f700bd6a1f1138edfd7a3cf7234c13a03b01a023a30aa53e6bd5e6a50fdcdcf74587c9395b8a314690abbc85aadab5ebcb7678994eacf1b',
paymaster: '0xfd9ae5ebb0f6656f4b77a0e99dcbc5138d54b0ba',
paymasterInput:
'0x8c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000',
})
})

test('not eip712 transaction', () => {
const serializedTransaction =
'0x73a20167b8d23b610b058c05368174495adf7da3a4ed4a57eb6dbdeb1fafc24aaf87530d663a0d061f69bb564d2c6fb46ae5ae776bbd4bd2a2a4478b9cd1b42a'

try {
parseEip712Transaction(serializedTransaction)
} catch (e: any) {
expect(e.shortMessage).toEqual('transaction type must be eip712')
}
})
57 changes: 57 additions & 0 deletions src/zksync/utils/parseEip712Transaction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { BaseError } from '../../errors/base.js'
import type { Hex } from '../../types/misc.js'
import {
fromHex,
fromRlp,
hexToBigInt,
hexToNumber,
} from '../../utils/index.js'
import type { ZksyncTransactionSerializableEIP712 } from '../types/transaction.js'

export function parseEip712Transaction(
transaction: Hex,
): ZksyncTransactionSerializableEIP712 {
const payload = fromHex(transaction, 'bytes')
if (payload[0] !== 113) throw new BaseError('transaction type must be eip712')

function validHex(value: Hex): Hex {
if (!value || value === '0x') return '0x0'
return value
}

function parsePaymasterArray(arr: Hex[]) {
if (arr.length === 0) return undefined
if (arr.length !== 2)
throw new BaseError(
`Invalid paymaster parameters, expected to have length of 2, found ${arr.length}!`,
)

return {
paymaster: arr[0],
paymasterInput: arr[1],
}
}

const raw = fromRlp(payload.slice(1)) as Hex[]
const paymasterParams = parsePaymasterArray(raw[15] as unknown as Hex[])
return {
type: 'eip712',
nonce: hexToNumber(validHex(raw[0])),
maxPriorityFeePerGas: hexToBigInt(validHex(raw[1])),
maxFeePerGas: hexToBigInt(validHex(raw[2])),
gas: hexToBigInt(validHex(raw[3])),
to: raw[4],
value: hexToBigInt(validHex(raw[5])),
data: raw[6],
v: hexToBigInt(validHex(raw[7])),
r: raw[8],
s: raw[9],
chainId: hexToNumber(validHex(raw[10])),
from: raw[11],
gasPerPubdata: hexToBigInt(validHex(raw[12])),
factoryDeps: raw[13] as unknown as Hex[],
customSignature: raw[14],
paymaster: paymasterParams?.paymaster,
paymasterInput: paymasterParams?.paymasterInput,
}
}

0 comments on commit dbd72a4

Please sign in to comment.